mirror of
https://github.com/Kistler-Group/sdbus-cpp.git
synced 2026-08-28 16:02:37 +02:00
Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bce1da5a2e | ||
|
|
c8fb8caeb9 | ||
|
|
fbb4a23e62 | ||
|
|
341a1f3aee | ||
|
|
e62525ca4f | ||
|
|
e50ce7c37f | ||
|
|
2ff5a09432 | ||
|
|
10f701df74 | ||
|
|
94b8058dc5 | ||
|
|
cda14c9702 | ||
|
|
4b6fa20491 | ||
|
|
7c402b5ba9 | ||
|
|
f7afe3d1b1 | ||
|
|
18aece04d5 | ||
|
|
9092bbd44c | ||
|
|
fe773958d1 | ||
|
|
bdd0bc2c27 | ||
|
|
e3040c0998 | ||
|
|
29bae0aaa8 | ||
|
|
8affda1678 | ||
|
|
58358eefa1 | ||
|
|
8c8e40dc9d | ||
|
|
f38d578478 | ||
|
|
071e38c9de | ||
|
|
21dd77ba6c | ||
|
|
2ef0e78ad2 | ||
|
|
ab2032592b | ||
|
|
a7ae2ef79f | ||
|
|
e87a252493 | ||
|
|
37a7b311d6 | ||
|
|
e95024192c | ||
|
|
8d24b2826e | ||
|
|
0f99724449 |
-66
@@ -1,66 +0,0 @@
|
||||
---
|
||||
# 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'
|
||||
+51
-49
@@ -14,11 +14,18 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-24.04]
|
||||
os: [ubuntu-20.04, ubuntu-22.04]
|
||||
compiler: [g++, clang]
|
||||
build: [shared-libsystemd, embedded-static-libsystemd]
|
||||
build: [shared-libsystemd]
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
compiler: g++
|
||||
build: embedded-static-libsystemd
|
||||
- os: ubuntu-22.04
|
||||
compiler: clang
|
||||
build: embedded-static-libsystemd
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: install-libsystemd-toolchain
|
||||
if: matrix.build == 'embedded-static-libsystemd'
|
||||
run: |
|
||||
@@ -32,76 +39,71 @@ jobs:
|
||||
- name: install-clang
|
||||
if: matrix.compiler == 'clang'
|
||||
run: |
|
||||
sudo apt-get install -y clang libc++-dev
|
||||
sudo apt-get install -y 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
|
||||
# We need to use libc++ with Clang because there is a bug in libstdc++ chrono headers that Clang has issues with
|
||||
echo "SDBUSCPP_EXTRA_CXX_FLAGS=-stdlib=libc++" >> $GITHUB_ENV
|
||||
# We don't install googletest but we let it be built within sdbus-c++ builds below, since it needs to be built against libc++ for Clang jobs to pass
|
||||
# - name: install-googletest
|
||||
# run: |
|
||||
# sudo apt-get install -y libgmock-dev
|
||||
- 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'
|
||||
- name: install-googletest
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: |
|
||||
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
|
||||
sudo apt-get install -y libgmock-dev
|
||||
- name: install-googletest
|
||||
if: matrix.os == 'ubuntu-20.04' # On older ubuntus the libgmock-dev package is either unavailable or has faulty pkg-config file, so we build & install manually
|
||||
run: |
|
||||
git clone https://github.com/google/googletest.git
|
||||
cd googletest
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . -j4
|
||||
sudo cmake --build . --target install
|
||||
- name: configure-debug
|
||||
if: matrix.build == 'shared-libsystemd' && (matrix.compiler != 'g++' || matrix.os != 'ubuntu-22.04')
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
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
|
||||
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" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DBUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
- name: configure-release
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-22.04'
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
- name: configure-with-embedded-libsystemd
|
||||
if: matrix.build == 'embedded-static-libsystemd'
|
||||
run: |
|
||||
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
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_VERBOSE_MAKEFILE=ON -DSDBUSCPP_INSTALL=ON -DBUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DSDBUSCPP_BUILD_LIBSYSTEMD=ON -DSDBUSCPP_LIBSYSTEMD_VERSION=252 ..
|
||||
- name: make
|
||||
run: |
|
||||
cmake --build _build -j4
|
||||
cd build
|
||||
cmake --build . -j4
|
||||
- name: verify
|
||||
run: |
|
||||
sudo cmake --build _build --target install
|
||||
ctest --output-on-failure --test-dir _build
|
||||
cd build
|
||||
sudo cmake --build . --target install
|
||||
ctest --output-on-failure
|
||||
- name: pack
|
||||
if: matrix.build == 'shared-libsystemd'
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
cd _build
|
||||
cd build
|
||||
cpack -G DEB
|
||||
- name: 'Upload Artifact'
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.compiler == 'g++'
|
||||
uses: actions/upload-artifact@v4
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04' && matrix.compiler == 'g++'
|
||||
uses: actions/upload-artifact@v3
|
||||
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
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD VM
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
@@ -110,7 +112,7 @@ jobs:
|
||||
prepare: |
|
||||
pkg install -y cmake ninja pkgconf basu expat googletest
|
||||
run: |
|
||||
cmake -B _build -G Ninja -DSDBUSCPP_INSTALL=ON -DSDBUSCPP_BUILD_CODEGEN=ON -DSDBUSCPP_BUILD_TESTS=ON -DSDBUSCPP_BUILD_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON
|
||||
cmake -B _build -G Ninja -DSDBUSCPP_INSTALL=ON -DBUILD_CODE_GEN=ON -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DSDBUSCPP_BUILD_STRESS_TESTS=ON
|
||||
cmake --build _build
|
||||
cmake --install _build
|
||||
pkg install -y dbus
|
||||
|
||||
@@ -16,9 +16,6 @@ tests/run-test-on-device.sh
|
||||
.settings
|
||||
*.log
|
||||
|
||||
# vscode
|
||||
.vscode/
|
||||
|
||||
#autotools
|
||||
sdbus-cpp.pc
|
||||
*Makefile
|
||||
|
||||
+52
-87
@@ -4,7 +4,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(sdbus-c++ VERSION 2.3.0 LANGUAGES CXX C)
|
||||
project(sdbus-c++ VERSION 2.0.0 LANGUAGES C CXX)
|
||||
|
||||
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
|
||||
|
||||
@@ -12,22 +12,19 @@ include(GNUInstallDirs) # Installation directories for `install` command and pkg
|
||||
# CONFIGURATION OPTIONS
|
||||
# -------------------------------
|
||||
|
||||
option(SDBUSCPP_BUILD_LIBSYSTEMD "Fetch & build libsystemd static library and make it part of libsdbus-c++, instead of searching for it in the system" OFF)
|
||||
if(NOT SDBUSCPP_BUILD_LIBSYSTEMD)
|
||||
set(SDBUSCPP_SDBUS_LIB "default" CACHE STRING "sd-bus implementation library to search for and use (default, systemd, elogind, or basu)")
|
||||
set_property(CACHE SDBUSCPP_SDBUS_LIB PROPERTY STRINGS default systemd elogind basu)
|
||||
else()
|
||||
set(SDBUSCPP_LIBSYSTEMD_VERSION "252" CACHE STRING "libsystemd version (>=239) to build and incorporate into libsdbus-c++")
|
||||
option(SDBUSCPP_BUILD_LIBSYSTEMD "Fetch & build libsystemd static library and make it part of libsdbus-c++, instead of searching for libsystemd in the system" OFF)
|
||||
if(SDBUSCPP_BUILD_LIBSYSTEMD)
|
||||
set(SDBUSCPP_LIBSYSTEMD_VERSION "242" CACHE STRING "libsystemd version (>=239) to build and incorporate into libsdbus-c++")
|
||||
set(SDBUSCPP_LIBSYSTEMD_EXTRA_CONFIG_OPTS "" CACHE STRING "Additional configuration options to be passed as-is to libsystemd build system")
|
||||
endif()
|
||||
option(SDBUSCPP_INSTALL "Enable installation of sdbus-c++ (downstream projects embedding sdbus-c++ may want to turn this OFF)" ON)
|
||||
option(SDBUSCPP_BUILD_TESTS "Build tests" OFF)
|
||||
if (SDBUSCPP_BUILD_TESTS)
|
||||
option(SDBUSCPP_BUILD_PERF_TESTS "Build also sdbus-c++ performance tests" OFF)
|
||||
option(SDBUSCPP_BUILD_STRESS_TESTS "Build also sdbus-c++ stress tests" OFF)
|
||||
set(SDBUSCPP_TESTS_INSTALL_PATH "tests/${PROJECT_NAME}" CACHE STRING "Specifies where the test binaries will be installed")
|
||||
set(SDBUSCPP_GOOGLETEST_VERSION 1.14.0 CACHE STRING "Version of gmock library to use")
|
||||
set(SDBUSCPP_GOOGLETEST_GIT_REPO "https://github.com/google/googletest.git" CACHE STRING "A git repo to clone and build googletest from if gmock is not found in the system")
|
||||
option(SDBUSCPP_BUILD_PERF_TESTS "Build also sdbus-c++ performance tests" OFF) # tranferred from tests/cmake
|
||||
option(SDBUSCPP_BUILD_STRESS_TESTS "Build also sdbus-c++ stress tests" OFF) # tranferred from tests/cmake
|
||||
set(SDBUSCPP_TESTS_INSTALL_PATH "tests/${PROJECT_NAME}" CACHE STRING "Specifies where the test binaries will be installed") # tranferred from tests/cmake
|
||||
set(SDBUSCPP_GOOGLETEST_VERSION 1.10.0 CACHE STRING "Version of gmock library to use") # tranferred from tests/cmake
|
||||
set(SDBUSCPP_GOOGLETEST_GIT_REPO "https://github.com/google/googletest.git" CACHE STRING "A git repo to clone and build googletest from if gmock is not found in the system") # tranferred from tests/cmake
|
||||
endif()
|
||||
option(SDBUSCPP_BUILD_CODEGEN "Build generator tool for C++ native bindings" OFF)
|
||||
option(SDBUSCPP_BUILD_EXAMPLES "Build example programs" OFF)
|
||||
@@ -35,7 +32,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)
|
||||
@@ -74,64 +71,47 @@ message(STATUS "")
|
||||
# PERFORMING CHECKS & PREPARING THE DEPENDENCIES
|
||||
#-------------------------------
|
||||
|
||||
if(SDBUSCPP_BUILD_LIBSYSTEMD)
|
||||
# Build static libsystemd library as an external project
|
||||
include(cmake/LibsystemdExternalProject.cmake)
|
||||
set(SDBUS_IMPL "systemd")
|
||||
set(SDBUS_LIB "libsystemd")
|
||||
else()
|
||||
# Search for sd-bus implementations in the system as per user's configuration
|
||||
set(SDBUS_LIBS ${SDBUSCPP_SDBUS_LIB})
|
||||
if(SDBUSCPP_SDBUS_LIB STREQUAL "default")
|
||||
set(SDBUS_LIBS systemd elogind basu) # This is the default search order
|
||||
endif()
|
||||
|
||||
set(MINIMUM_SDBUS_VERSION 238)
|
||||
set(LIBSYSTEMD_IMPL "systemd")
|
||||
set(LIBSYSTEMD_LIB "libsystemd")
|
||||
|
||||
if(NOT SDBUSCPP_BUILD_LIBSYSTEMD)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
foreach(LIB ${SDBUS_LIBS})
|
||||
if(LIB STREQUAL "systemd")
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libsystemd>=${MINIMUM_SDBUS_VERSION})
|
||||
if(TARGET PkgConfig::Systemd)
|
||||
set(SDBUS_IMPL "systemd")
|
||||
set(SDBUS_LIB "libsystemd")
|
||||
break()
|
||||
endif()
|
||||
elseif(LIB STREQUAL "elogind")
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libelogind>=${MINIMUM_SDBUS_VERSION})
|
||||
if(TARGET PkgConfig::Systemd)
|
||||
set(SDBUS_IMPL "elogind")
|
||||
set(SDBUS_LIB "libelogind")
|
||||
string(REPLACE "." ";" VERSION_LIST ${Systemd_VERSION})
|
||||
list(GET VERSION_LIST 0 Systemd_VERSION)
|
||||
break()
|
||||
endif()
|
||||
elseif(LIB STREQUAL "basu")
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL basu)
|
||||
if(TARGET PkgConfig::Systemd)
|
||||
set(SDBUS_IMPL "basu")
|
||||
set(SDBUS_LIB "basu")
|
||||
set(Systemd_VERSION "240") # https://git.sr.ht/~emersion/basu/commit/d4d185d29a26
|
||||
break()
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Unrecognized sd-bus implementation library ${LIB}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libsystemd>=238)
|
||||
if(NOT TARGET PkgConfig::Systemd)
|
||||
message(FATAL_ERROR "None of ${SDBUS_LIBS} libraries implementing sd-bus was found (Are their dev packages installed?)")
|
||||
message(WARNING "libsystemd not found, checking for libelogind instead")
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libelogind>=238)
|
||||
if(TARGET PkgConfig::Systemd)
|
||||
set(LIBSYSTEMD_IMPL "elogind")
|
||||
set(LIBSYSTEMD_LIB "libelogind")
|
||||
string(REPLACE "." ";" VERSION_LIST ${Systemd_VERSION})
|
||||
list(GET VERSION_LIST 0 Systemd_VERSION)
|
||||
else()
|
||||
message(WARNING "libelogind not found, checking for basu instead")
|
||||
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL basu)
|
||||
set(LIBSYSTEMD_IMPL "basu")
|
||||
set(LIBSYSTEMD_LIB "basu")
|
||||
# https://git.sr.ht/~emersion/basu/commit/d4d185d29a26
|
||||
set(Systemd_VERSION "240")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT TARGET PkgConfig::Systemd)
|
||||
message(FATAL_ERROR "libsystemd of version at least 238 is required, but was not found "
|
||||
"(if you have systemd in your OS, you may want to install package containing pkgconfig "
|
||||
" files for libsystemd library. On Ubuntu, that is libsystemd-dev. "
|
||||
" Alternatively, you may turn SDBUSCPP_BUILD_LIBSYSTEMD on for sdbus-c++ to download, "
|
||||
" build and incorporate libsystemd as embedded library within sdbus-c++)")
|
||||
endif()
|
||||
add_library(Systemd::Libsystemd ALIAS PkgConfig::Systemd)
|
||||
string(REGEX MATCHALL "([0-9]+)" SYSTEMD_VERSION_LIST "${Systemd_VERSION}")
|
||||
list(GET SYSTEMD_VERSION_LIST 0 SDBUSCPP_LIBSYSTEMD_VERSION)
|
||||
message(STATUS "Building with libsystemd v${SDBUSCPP_LIBSYSTEMD_VERSION}")
|
||||
else()
|
||||
# Build static libsystemd library as an external project
|
||||
include(cmake/LibsystemdExternalProject.cmake)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
include(cmake/clang-tidy.cmake) # Static analysis with clang-tidy
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
@@ -164,7 +144,6 @@ 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
|
||||
@@ -189,7 +168,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 17)
|
||||
|
||||
#----------------------------------
|
||||
# LIBRARY BUILD INFORMATION
|
||||
@@ -203,8 +182,8 @@ add_library(sdbus-c++-objlib OBJECT ${SDBUSCPP_SRCS})
|
||||
target_compile_definitions(sdbus-c++-objlib PRIVATE
|
||||
BUILD_LIB=1
|
||||
LIBSYSTEMD_VERSION=${SDBUSCPP_LIBSYSTEMD_VERSION}
|
||||
SDBUS_${SDBUS_IMPL}
|
||||
SDBUS_HEADER=<${SDBUS_IMPL}/sd-bus.h>)
|
||||
SDBUS_${LIBSYSTEMD_IMPL}
|
||||
SDBUS_HEADER=<${LIBSYSTEMD_IMPL}/sd-bus.h>)
|
||||
target_include_directories(sdbus-c++-objlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
@@ -219,9 +198,6 @@ 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++
|
||||
@@ -283,27 +259,18 @@ if(BUILD_SHARED_LIBS AND (SDBUSCPP_BUILD_LIBSYSTEMD OR Systemd_LINK_LIBRARIES MA
|
||||
else()
|
||||
set(PKGCONFIG_REQS "")
|
||||
endif()
|
||||
set(PKGCONFIG_DEPS ${SDBUS_LIB})
|
||||
set(PKGCONFIG_DEPS ${LIBSYSTEMD_LIB})
|
||||
configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY)
|
||||
|
||||
#----------------------------------
|
||||
# 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
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
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
|
||||
@@ -333,18 +300,16 @@ 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 sdbus-c++-runtime sdbus-c++-dev sdbus-c++-doc)
|
||||
set(CPACK_COMPONENT_DEV_DEPENDS "sdbus-c++-runtime")
|
||||
set(CPACK_COMPONENTS_ALL runtime dev doc)
|
||||
set(CPACK_COMPONENT_DEV_DEPENDS "runtime")
|
||||
# specific for DEB generator
|
||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
||||
set(CPACK_DEBIAN_RUNTIME_DEBUGINFO_PACKAGE ON)
|
||||
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_RUNTIME_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS ON)
|
||||
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libsystemd-dev (>=${MINIMUM_SDBUS_VERSION})")
|
||||
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libsystemd-dev (>=236)")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -240,85 +240,12 @@ v1.4.0
|
||||
- Add option to create IConnection directly from an underlying sd_bus instance
|
||||
- Some additional fixes
|
||||
|
||||
v1.5.0
|
||||
- Improve handling of exceptions from callback handlers
|
||||
- Add support for async registration of matches
|
||||
- Correctly add libsystemd dependency to pkgconfi
|
||||
- Fix request name signal handling issue
|
||||
- Add INSTALL_TESTS CMake option
|
||||
- Minor UnixFd cleanups
|
||||
- Additional little fixes and updates in code, build system, CI, and documentation
|
||||
|
||||
v1.6.0
|
||||
- Add support for enums in D-Bus serialization and signatures
|
||||
- Add support for std::variant as an alternative C++ type for D-Bus Variant
|
||||
- Add support for implicit conversions between std::variant and sdbus::Variant
|
||||
- Fix missing includes
|
||||
|
||||
v2.0.0
|
||||
- A new major version with revamped API, bringing numerous new features, simplifications, fixes and breaking changes improving not only API consistency, safety and expressiveness, but also performance
|
||||
- Add section 'Migrating to sdbus-c++ v2' to the 'Using sdbus-c++' document providing the complete list of breaking API/ABI/behavior changes and migration notes
|
||||
- Switch to C++20 standard (but the API is backwards-compatible with C++17, skipping C++20 features in such a case)
|
||||
- Add strong types to public API
|
||||
- Add support for string_view as a D-Bus type representation
|
||||
- Enable compile-time D-Bus signature generation
|
||||
- Redesign Object vtable registration API
|
||||
- Improve Proxy signal subscription API
|
||||
- Refactor object manager API for consistency
|
||||
- Introduce native sd-event integration
|
||||
- Let callbacks take message objects by value
|
||||
- Simplify async D-Bus connection handling
|
||||
- Simplify async call state flag
|
||||
- Make Variant constructor explicit
|
||||
- Use optional for passing potential call errors
|
||||
- Rename and re-organize CMake options
|
||||
- Rename connection creation methods
|
||||
- Have all async function names finish with *Async for consistency
|
||||
- Implement more flexible searching for sd-bus libs
|
||||
- Add new `SDBUSCPP_SDBUS_LIB` CMake configuration variable determining which sd-bus library shall be picked
|
||||
- Make Variant conversion operator explicit
|
||||
- Use sd-bus API to get the current message
|
||||
- Use sd_bus_match_signal() for signal registration
|
||||
- Provide also const char* overloads for convenience functions
|
||||
- Disable move in generated adaptor and proxy classes
|
||||
- Improve and make more efficient some Message API
|
||||
- Add Slot-returning overloads of async method calls
|
||||
- Remove floating_slot_t tag and use return_slot_t instead
|
||||
- Add [[nodiscard]] to many relevant API functions
|
||||
- Add proper fix for timeout handling
|
||||
- A number of breaking changes in API/ABI/behavior and in the generated bindings. See the sdbus-c++ tutorial for the migration notes.
|
||||
- Systemd of at least v238 is required to compile sdbus-c++
|
||||
- A proper fix for timeout handling
|
||||
- Fix for external event loops in which the event loop thread ID was not correctly initialized (now fixed and simplified by not needing the thread ID anymore)
|
||||
- Remove deprecated stuff
|
||||
- Add `SDBUSCPP_` prefix to CMake configuration variables to avoid conflicts with downstream projects
|
||||
- Require systemd of at least v238
|
||||
- Many other fixes and updates in code, tests, build system, CI, and documentation
|
||||
|
||||
v2.1.0
|
||||
- Add SDBUSCPP_REGISTER_STRUCT macro to conveniently teach sdbus-c++ about user-defined structs
|
||||
- Extend the SDBUSCPP_REGISTER_STRUCT macro with serialization of user-defined structs as dicts, and deserialization of dicts into user-defined structs
|
||||
- Make createPlainMessage() function public
|
||||
- Solve the problem of sending large D-Bus messages properly (through the event loop thread)
|
||||
- Fix partially renamed BUILD_DOXYGEN_DOC CMake option
|
||||
- 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
|
||||
|
||||
v2.3.0
|
||||
- Add coroutine support for client-side async calls
|
||||
- Add support for dumping variant to string
|
||||
- Introduce clang-tidy for static analysis and fix issues
|
||||
- Add deduction guides for Struct from std::tuple
|
||||
- Other fixes and improvements
|
||||
- Introduce native integration for sd-event
|
||||
- Add method to get currently processed message also to `IConnection`
|
||||
- `[[nodiscard]]` attribute has been added to relevant API methods.
|
||||
- Other simplifications, improvements and fixes springing out from the above refactoring
|
||||
|
||||
@@ -28,74 +28,64 @@ $ sudo cmake --build . --target install
|
||||
|
||||
* `SDBUSCPP_BUILD_CODEGEN` [boolean]
|
||||
|
||||
Build the codegen tool `sdbus-c++-xml2cpp` for generating the high level C++ bindings out of the D-Bus IDL XML description. Default value: `OFF`. Use `-DSDBUSCPP_BUILD_CODEGEN=ON` flag to turn on building the code gen.
|
||||
Option for building the stub code generator `sdbus-c++-xml2cpp` for generating the adaptor and proxy interfaces out of the D-Bus IDL XML description. Default value: `OFF`. Use `-DSDBUSCPP_BUILD_CODEGEN=ON` flag to turn on building the code gen.
|
||||
|
||||
* `SDBUSCPP_BUILD_DOCS` [boolean]
|
||||
|
||||
Include sdbus-c++ documentation files and tutorials. Default value: `ON`. With this option turned on, you may also enable/disable the following option:
|
||||
Option for including sdbus-c++ documentation files and tutorials. Default value: `ON`. With this option turned on, you may also enable/disable the following option:
|
||||
|
||||
* `SDBUSCPP_BUILD_DOXYGEN_DOCS` [boolean]
|
||||
* `BUILD_DOXYGEN_DOC` [boolean]
|
||||
|
||||
Build Doxygen documentation of sdbus-c++ API. If enabled, the documentation must still be built explicitly through `cmake --build . --target doc`. Default value: `OFF`. Use `-DSDBUSCPP_BUILD_DOXYGEN_DOCS=OFF` to disable searching for Doxygen and building Doxygen documentation of sdbus-c++ API.
|
||||
Option for building Doxygen documentation of sdbus-c++ API. If enabled, the documentation must still be built explicitly through `cmake --build . --target doc`. Default value: `OFF`. Use `-DBUILD_DOXYGEN_DOC=OFF` to disable searching for Doxygen and building Doxygen documentation of sdbus-c++ API.
|
||||
|
||||
* `SDBUSCPP_BUILD_TESTS` [boolean]
|
||||
|
||||
Build sdbus-c++ unit and integration tests, invokable by `cmake --build . --target test` (Note: before invoking `cmake --build . --target test`, make sure you copy `tests/integrationtests/files/org.sdbuscpp.integrationtests.conf` file to `/etc/dbus-1/system.d` directory). That incorporates downloading and building static libraries of Google Test. Default value: `OFF`. Use `-DBUILD_TESTS=ON` to enable building the tests. With this option turned on, you may also enable/disable the following options:
|
||||
Option for building sdbus-c++ unit and integration tests, invokable by `cmake --build . --target test` (Note: before invoking `cmake --build . --target test`, make sure you copy `tests/integrationtests/files/org.sdbuscpp.integrationtests.conf` file to `/etc/dbus-1/system.d` directory). That incorporates downloading and building static libraries of Google Test. Default value: `OFF`. Use `-DBUILD_TESTS=ON` to enable building the tests. With this option turned on, you may also enable/disable the following options:
|
||||
|
||||
* `SDBUSCPP_BUILD_PERF_TESTS` [boolean]
|
||||
|
||||
Build sdbus-c++ performance tests. Default value: `OFF`.
|
||||
Option for building sdbus-c++ performance tests. Default value: `OFF`.
|
||||
|
||||
* `SDBUSCPP_BUILD_STRESS_TESTS` [boolean]
|
||||
|
||||
Build sdbus-c++ stress tests. Default value: `OFF`.
|
||||
Option for building sdbus-c++ stress tests. Default value: `OFF`.
|
||||
|
||||
* `SDBUSCPP_TESTS_INSTALL_PATH` [string]
|
||||
|
||||
Path where the test binaries shall get installed. Default value: `${CMAKE_INSTALL_PREFIX}/tests/sdbus-c++` (previously: `/opt/test/bin`).
|
||||
|
||||
* `SDBUSCPP_BUILD_EXAMPLES` [boolean]
|
||||
|
||||
Build example programs which are located in the _example_ directory. Examples are not installed. Default value: `OFF`.
|
||||
|
||||
* `SDBUSCPP_BUILD_LIBSYSTEMD` [boolean]
|
||||
|
||||
Build sd-bus (libsystemd library) instead of searching for it in the system, and make it part of sdbus-c++ library. Default value: `OFF`, which means that the sd-bus implementation library (`libsystemd`, `libelogind`, or `basu`) will be searched via `pkg-config` in the system.
|
||||
|
||||
This option may be very helpful in environments where sd-bus implementation library is unavailable (see [Solving sd-bus dependency](docs/using-sdbus-c++.md#solving-sd-bus-dependency) for more information).
|
||||
|
||||
With this option turned off, you may provide the following additional configuration flag:
|
||||
|
||||
* `SDBUSCPP_SDBUS_LIB` [string]
|
||||
|
||||
Defines which sd-bus implementation library to search for and use. Allowed values: `default`, `systemd`, `elogind`, `basu`. Default value: `default`, which means that sdbus-c++ will try to find any of `systemd`, `elogind`, `basu` in the order as listed here.
|
||||
|
||||
With this option turned on, you may provide the following additional configuration flag:
|
||||
Option for building libsystemd dependency library automatically when sdbus-c++ is built, and making libsystemd an integral part of sdbus-c++ library. Default value: `OFF`. Might be very helpful in non-systemd environments where libsystemd shared library is unavailable (see [Solving libsystemd dependency](docs/using-sdbus-c++.md#solving-libsystemd-dependency) for more information). With this option turned on, you may also provide the following configuration flag:
|
||||
|
||||
* `SDBUSCPP_LIBSYSTEMD_VERSION` [string]
|
||||
|
||||
Defines version of systemd to be downloaded, built and integrated into sdbus-c++. Default value: `252`, minimum value: `239`.
|
||||
Defines version of systemd to be downloaded, built and integrated into sdbus-c++. Default value: `242`.
|
||||
|
||||
* `SDBUSCPP_LIBSYSTEMD_EXTRA_CONFIG_OPTS` [string]
|
||||
|
||||
Additional options to be passed as-is to the libsystemd build system in its configure step. Can be used for passing e.g. toolchain file path in case of cross builds. Default value: empty.
|
||||
Additional options to be passed as-is to the libsystemd build system (meson for systemd v242) in its configure step. Can be used for passing e.g. toolchain file path in case of cross builds. Default value: empty.
|
||||
|
||||
* `CMAKE_BUILD_TYPE` [string]
|
||||
|
||||
CMake-builtin option. Set to `Release` to build sdbus-c++ for production use. Set to `Debug` if you want to help further develop (and debug) the library :)
|
||||
This is a CMake-builtin option. Set to `Release` to build sdbus-c++ for production use. Set to `Debug` if you want to help further develop (and debug) the library :)
|
||||
|
||||
* `BUILD_SHARED_LIBS` [boolean]
|
||||
|
||||
Global CMake flag, promoted in sdbus-c++ project to a CMake option. Use this to control whether sdbus-c++ is built as either a shared or static library. Default value: `ON`.
|
||||
This is a global CMake flag, promoted in sdbus-c++ project to a CMake option. Use this to control whether sdbus-c++ is built as either a shared or static library. Default value: `ON`.
|
||||
|
||||
* `SDBUSCPP_BUILD_EXAMPLES` [boolean]
|
||||
|
||||
Build example programs which are located in the _example_ directory. Examples are not installed. Default value: `OFF`
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* `C++20/C++17` - the library uses C++20 features, but its public API is backwards compatible with C++17 and provides optional extra features when C++20 features are available
|
||||
* `libsystemd`/`libelogind`/`basu` - libraries containing sd-bus implementation that sdbus-c++ is written around. In case of `libsystemd` and `libelogind`, version >= 238 is needed. (In case you have you're missing any of those sd-bus implementations, don't worry, see [Solving sd-bus dependency](docs/using-sdbus-c++.md#solving-sd-bus-dependency) for more information.)
|
||||
* `C++17` - the library uses C++17 features.
|
||||
* `libsystemd`/`libelogind`/`basu` - libraries containing sd-bus implementation that sdbus-c++ is written around. In case of `libsystemd` and `libelogind`, version >= 236 is needed. (In case you have a non-systemd environment, don't worry, see [Solving libsystemd dependency](docs/using-sdbus-c++.md#solving-libsystemd-dependency) for more information.)
|
||||
* `googletest` - google unit testing framework, only necessary when building tests, will be downloaded and built automatically.
|
||||
* `pkgconfig` - required for sdbus-c++ to be able to find some dependency packages.
|
||||
* `expat` - necessary when building the xml2cpp binding code generator (`SDBUSCPP_BUILD_CODEGEN` option is `ON`).
|
||||
* `expat` - necessary when building the xml2cpp binding code generator (`SDBUSCPP_BUILD_CODEGEN` option is ON).
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#----------------------------------
|
||||
# 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()
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
find_package(Doxygen)
|
||||
|
||||
if(SDBUSCPP_BUILD_DOXYGEN_DOCS)
|
||||
if(BUILD_DOXYGEN_DOC)
|
||||
if(DOXYGEN_FOUND)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||
|
||||
@@ -27,7 +27,7 @@ if(SDBUSCPP_INSTALL)
|
||||
using-sdbus-c++.md
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT sdbus-c++-doc)
|
||||
|
||||
if (SDBUSCPP_BUILD_DOXYGEN_DOCS AND DOXYGEN_FOUND)
|
||||
if (BUILD_DOXYGEN_DOC AND DOXYGEN_FOUND)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL COMPONENT sdbus-c++-doc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
+140
-309
@@ -5,7 +5,7 @@ Using sdbus-c++ library
|
||||
|
||||
1. [Introduction](#introduction)
|
||||
2. [Integrating sdbus-c++ into your project](#integrating-sdbus-c-into-your-project)
|
||||
3. [Solving sd-bus dependency](#solving-sd-bus-dependency)
|
||||
3. [Solving libsystemd dependency](#solving-libsystemd-dependency)
|
||||
4. [Distributing sdbus-c++](#distributing-sdbus-c)
|
||||
5. [Header files and namespaces](#header-files-and-namespaces)
|
||||
6. [Error signalling and propagation](#error-signalling-and-propagation)
|
||||
@@ -20,12 +20,11 @@ Using sdbus-c++ library
|
||||
15. [Using D-Bus properties](#using-d-bus-properties)
|
||||
16. [Standard D-Bus interfaces](#standard-d-bus-interfaces)
|
||||
17. [Representing D-Bus Types in sdbus-c++](#representing-d-bus-types-in-sdbus-c)
|
||||
18. [Adding user-defined types to the sdbus-c++ type system](#adding-user-defined-types-to-the-sdbus-c-type-system)
|
||||
19. [Support for match rules](#support-for-match-rules)
|
||||
20. [Using direct (peer-to-peer) D-Bus connections](#using-direct-peer-to-peer-d-bus-connections)
|
||||
21. [Using sdbus-c++ in external event loops](#using-sdbus-c-in-external-event-loops)
|
||||
22. [Migrating to sdbus-c++ v2](#migrating-to-sdbus-c-v2)
|
||||
23. [Conclusion](#conclusion)
|
||||
18. [Support for match rules](#support-for-match-rules)
|
||||
19. [Using direct (peer-to-peer) D-Bus connections](#using-direct-peer-to-peer-d-bus-connections)
|
||||
20. [Using sdbus-c++ in external event loops](#using-sdbus-c-in-external-event-loops)
|
||||
21. [Migrating to sdbus-c++ v2](#migrating-to-sdbus-c-v2)
|
||||
22. [Conclusion](#conclusion)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
@@ -57,7 +56,7 @@ PKG_CHECK_MODULES(SDBUSCPP, [sdbus-c++ >= 0.6],,
|
||||
)
|
||||
```
|
||||
|
||||
> **_Note_:** sdbus-c++ library uses a number of modern C++17 (and, conditionally, C++20) features. Please make sure you have a recent compiler (best gcc >= 10, clang >= 11).
|
||||
> **_Note_:** sdbus-c++ library uses a number of modern C++17 features. Please make certain you have a recent compiler (gcc >= 7, clang >= 6).
|
||||
|
||||
If you intend to use xml-to-c++ generator tool (explained later) in your project to generate interface headers from XML, you can integrate that too with CMake or `pkg-config`:
|
||||
|
||||
@@ -75,14 +74,14 @@ add_custom_command(
|
||||
)
|
||||
```
|
||||
|
||||
Solving sd-bus dependency
|
||||
-------------------------
|
||||
Solving libsystemd dependency
|
||||
-----------------------------
|
||||
|
||||
sdbus-c++ is a wrapper around sd-bus, a C library that has been written as part of [systemd](https://github.com/systemd/systemd) project.
|
||||
sdbus-c++ depends on sd-bus API, which is implemented in libsystemd, a C library that is part of [systemd](https://github.com/systemd/systemd).
|
||||
|
||||
Within systemd, sd-bus is implemented as part of `libsystemd` shared library. At least version 0.22.0 (which corresponds to the minimum systemd version 238) of `libsystemd` is needed.
|
||||
Minimum required libsystemd shared library version is 0.20.0 (which corresponds to minimum systemd version 236).
|
||||
|
||||
If your target Linux distribution is already based on systemd ecosystem of version 238 and higher, then there is no additional effort, just make sure you have corresponding systemd header files available (provided by `libsystemd-dev` package on Debian/Ubuntu, for example), and you may go on building sdbus-c++ seamlessly.
|
||||
If your target Linux distribution is already based on systemd ecosystem of version 236 and higher, then there is no additional effort, just make sure you have corresponding systemd header files available (provided by `libsystemd-dev` package on Debian/Ubuntu, for example), and you may go on building sdbus-c++ seamlessly.
|
||||
|
||||
However, sdbus-c++ can perfectly be used in non-systemd environments as well. If `libsystemd` is not found in the system when configuring sdbus-c++, then
|
||||
|
||||
@@ -90,9 +89,7 @@ However, sdbus-c++ can perfectly be used in non-systemd environments as well. If
|
||||
|
||||
2. sdbus-c++ will try to find `basu`, which is just sd-bus implementation extracted from systemd.
|
||||
|
||||
Alternatively to this fallback search sequence, you may explicitly instruct sdbus-c++ to use a specified sd-bus implementation through the `SDBUSCPP_SDBUS_LIB` CMake configuration option.
|
||||
|
||||
On systems where neither of those libraries is available, we can build sd-bus manually, or we can (conveniently) instruct sdbus-c++ to build and integrate sd-bus into itself for us.
|
||||
On systems where neither of these is available, we can build sd-bus as a shared lib manually or we can (conveniently) instruct sdbus-c++ to build and integrate sd-bus into itself for us.
|
||||
|
||||
### Building and distributing libsystemd as a shared library yourself
|
||||
|
||||
@@ -114,7 +111,7 @@ $ ninja libsystemd.so.0.26.0 # or another version number depending which system
|
||||
|
||||
sdbus-c++ provides `SDBUSCPP_BUILD_LIBSYSTEMD` configuration option. When turned on, sdbus-c++ will automatically download and build libsystemd as a static library and make it an opaque part of sdbus-c++ shared library for you. This is the most convenient and effective approach to build, distribute and use sdbus-c++ as a self-contained, systemd-independent library in non-systemd environments. Just make sure your build machine has all dependencies needed by libsystemd build process. That includes, among others, `meson`, `ninja`, `git`, `gperf`, and -- primarily -- libraries and library headers for `libmount`, `libcap` and `librt` (part of glibc). Also, when distributing, make sure these dependency libraries are installed on the production machine.
|
||||
|
||||
You may additionally set the `SDBUSCPP_LIBSYSTEMD_VERSION` configuration flag to fine-tune the version of systemd to be taken in. (The default value is 242, the minimum value is 239).
|
||||
You may additionally set the `SDBUSCPP_LIBSYSTEMD_VERSION` configuration flag to fine-tune the version of systemd to be taken in. (The default value is 242).
|
||||
|
||||
Distributing sdbus-c++
|
||||
----------------------
|
||||
@@ -185,7 +182,7 @@ The following diagram illustrates the major entities in sdbus-c++.
|
||||
|
||||

|
||||
|
||||
`IConnection` represents the concept of a D-Bus connection. You can connect to either the system bus or a session bus. Services can assign well-known service names to those connections. An I/O event loop should be run on the bus connection.
|
||||
`IConnection` represents the concept of a D-Bus connection. You can connect to either the system bus or a session bus. Services can assign unique service names to those connections. An I/O event loop should be run on the bus connection.
|
||||
|
||||
`IObject` represents the concept of an object that exposes its methods, signals and properties. Its responsibilities are:
|
||||
|
||||
@@ -239,7 +236,7 @@ Let's have an object `/org/sdbuscpp/concatenator` that implements the `org.sdbus
|
||||
|
||||
In the following sections, we will elaborate on the ways of implementing such an object on both the server and the client side.
|
||||
|
||||
> **Before running Concatenator example in your system:** In order for your service to be allowed to provide a D-Bus API on ** the system bus**, a D-Bus security policy file has to be put in place for that service. Otherwise the service will fail to start (you'll get `[org.freedesktop.DBus.Error.AccessDenied] Failed to request bus name (Permission denied)`, for example). To make the Concatenator example work in your system, [look in this section of systemd configuration](systemd-dbus-config.md#dbus-configuration) for how to name the file, where to place it, how to populate it. For further information, consult [dbus-daemon documentation](https://dbus.freedesktop.org/doc/dbus-daemon.1.html), sections *INTEGRATING SYSTEM SERVICES* and *CONFIGURATION FILE*. As an example used for sdbus-c++ integration tests, you may look at the [policy file for sdbus-c++ integration tests](/tests/integrationtests/files/org.sdbuscpp.integrationtests.conf).
|
||||
> **Before running Concatenator example in your system:** In order for your service to be allowed to provide a D-Bus API on system bus, a D-Bus security policy file has to be put in place for that service. Otherwise the service will fail to start (you'll get `[org.freedesktop.DBus.Error.AccessDenied] Failed to request bus name (Permission denied)`, for example). To make the Concatenator example work in your system, [look in this section of systemd configuration](systemd-dbus-config.md#dbus-configuration) for how to name the file, where to place it, how to populate it. For further information, consult [dbus-daemon documentation](https://dbus.freedesktop.org/doc/dbus-daemon.1.html), sections *INTEGRATING SYSTEM SERVICES* and *CONFIGURATION FILE*. As an example used for sdbus-c++ integration tests, you may look at the [policy file for sdbus-c++ integration tests](/tests/integrationtests/files/org.sdbuscpp.integrationtests.conf).
|
||||
|
||||
Implementing the Concatenator example using basic sdbus-c++ API layer
|
||||
---------------------------------------------------------------------
|
||||
@@ -276,7 +273,7 @@ void concatenate(sdbus::MethodCall call)
|
||||
|
||||
// Return error if there are no numbers in the collection
|
||||
if (numbers.empty())
|
||||
throw sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.Concatenator.Error"}, "No numbers provided");
|
||||
throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
|
||||
|
||||
std::string result;
|
||||
for (auto number : numbers)
|
||||
@@ -290,29 +287,28 @@ void concatenate(sdbus::MethodCall call)
|
||||
reply.send();
|
||||
|
||||
// Emit 'concatenated' signal
|
||||
sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
|
||||
sdbus::SignalName signalName{"concatenated"};
|
||||
auto signal = g_concatenator->createSignal(interfaceName, signalName);
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
auto signal = g_concatenator->createSignal(interfaceName, "concatenated");
|
||||
signal << result;
|
||||
g_concatenator->emitSignal(signal);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create D-Bus connection to (either the session or system) bus and requests a well-known name on it.
|
||||
sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"};
|
||||
auto connection = sdbus::createBusConnection(serviceName);
|
||||
// Create D-Bus connection to the system bus and requests name on it.
|
||||
const char* serviceName = "org.sdbuscpp.concatenator";
|
||||
auto connection = sdbus::createSystemBusConnection(serviceName);
|
||||
|
||||
// Create concatenator D-Bus object.
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
auto concatenator = sdbus::createObject(*connection, std::move(objectPath));
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
auto concatenator = sdbus::createObject(*connection, objectPath);
|
||||
|
||||
g_concatenator = concatenator.get();
|
||||
|
||||
// Register D-Bus methods and signals on the concatenator object, and exports the object.
|
||||
sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
|
||||
concatenator->addVTable( sdbus::MethodVTableItem{sdbus::MethodName{"concatenate"}, sdbus::Signature{"ais"}, {}, sdbus::Signature{"s"}, {}, &concatenate, {}}
|
||||
, sdbus::SignalVTableItem{sdbus::MethodName{"concatenated"}, sdbus::Signature{"s"}, {}, {}} )
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenator->addVTable( sdbus::MethodVTableItem{"concatenate", "ais", {}, "s", {}, &concatenate, {}}
|
||||
, sdbus::SignalVTableItem{"concatenated", "s", {}, {}} )
|
||||
.forInterface(interfaceName);
|
||||
|
||||
// Run the I/O event loop on the bus connection.
|
||||
@@ -351,24 +347,21 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// Create proxy object for the concatenator object on the server side. Since here
|
||||
// we are creating the proxy instance without passing connection to it, the proxy
|
||||
// will create its own connection automatically (to either system bus or session bus,
|
||||
// depending on the context).
|
||||
sdbus::ServiceName destination{"org.sdbuscpp.concatenator"};
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
auto concatenatorProxy = sdbus::createProxy(std::move(destination), std::move(objectPath));
|
||||
// will create its own connection automatically, and it will be system bus connection.
|
||||
const char* destinationName = "org.sdbuscpp.concatenator";
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
auto concatenatorProxy = sdbus::createProxy(destinationName, objectPath);
|
||||
|
||||
// Let's subscribe for the 'concatenated' signals
|
||||
sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
|
||||
sdbus::SignalName signalName{"concatenated"};
|
||||
concatenatorProxy->registerSignalHandler(interfaceName, signalName, &onConcatenated);
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenatorProxy->registerSignalHandler(interfaceName, "concatenated", &onConcatenated);
|
||||
|
||||
std::vector<int> numbers = {1, 2, 3};
|
||||
std::string separator = ":";
|
||||
|
||||
sdbus::MethodName concatenate{"concatenate"};
|
||||
// Invoke concatenate on given interface of the object
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << numbers << separator;
|
||||
auto reply = concatenatorProxy->callMethod(method);
|
||||
std::string result;
|
||||
@@ -376,9 +369,9 @@ int main(int argc, char *argv[])
|
||||
assert(result == "1:2:3");
|
||||
}
|
||||
|
||||
// Invoke concatenate again, this time with no numbers and we shall get an error
|
||||
/ // Invoke concatenate again, this time with no numbers and we shall get an error
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << std::vector<int>() << separator;
|
||||
try
|
||||
{
|
||||
@@ -413,11 +406,11 @@ Please note that we can create and destroy D-Bus object proxies dynamically, at
|
||||
There are several factory methods to create a bus connection object in sdbus-c++:
|
||||
|
||||
* `createBusConnection()` - opens a connection to the session bus when in a user context, and a connection to the system bus, otherwise
|
||||
* `createBusConnection(const sdbus::ServiceName& name)` - opens a connection to the session bus when in a user context, and a connection with the given name to the system bus, otherwise, and requests the given well-known service name on the bus
|
||||
* `createBusConnection(const std::string& name)` - opens a connection with the given name to the session bus when in a user context, and a connection with the given name to the system bus, otherwise
|
||||
* `createSystemBusConnection()` - opens a connection to the system bus
|
||||
* `createSystemBusConnection(const sdbus::ServiceName& name)` - opens a connection to the system bus, and requests the given well-known service name on the bus
|
||||
* `createSystemBusConnection(const std::string& name)` - opens a connection with the given name to the system bus
|
||||
* `createSessionBusConnection()` - opens a connection to the session bus
|
||||
* `createSessionBusConnection(const sdbus::ServiceName& name)` - opens a connection to the session bus, and requests the given well-known service name on the bus.
|
||||
* `createSessionBusConnection(const std::string& name)` - opens a connection with the given name to the session bus
|
||||
* `createSessionBusConnectionWithAddress(const std::string& address)` - opens a connection to the session bus at a custom address
|
||||
* `createRemoteSystemBusConnection(const std::string& host)` - opens a connection to the system bus on a remote host using ssh
|
||||
* `createDirectBusConnection(const std::string& address)` - opens direct D-Bus connection at a custom address (see [Using direct (peer-to-peer) D-Bus connections](#using-direct-peer-to-peer-d-bus-connections))
|
||||
@@ -466,18 +459,18 @@ On the **client** side we likewise need a connection -- just that unlike on the
|
||||
|
||||
* Pass an already existing connection as a reference. This is the typical approach when the application already maintains a D-Bus connection (maybe it provide D-Bus API on it, and/or it already has some proxies hooked on it). The proxy will share the connection with others. With this approach we must of course ensure that the connection exists as long as the proxy exists. For discussion on options for running an event loop on that connection, see above section [Using D-Bus connections on the server side](#using-d-bus-connections-on-the-server-side).
|
||||
|
||||
* Or -- and this is a simpler approach for simple D-Bus client applications -- we have another option: we let the proxy maintain its own connection (and potentially an associated event loop thread, see below). We have two options here:
|
||||
* Or -- and this is a simpler approach for simple D-Bus client applications -- we have another option: we let the proxy maintain its own connection (and potentially an associated event loop thread, see below). We have two options here:
|
||||
|
||||
* We either create the connection ourselves and `std::move` it to the proxy object factory. The proxy becomes an owner of this connection, and it will be his dedicated connection. This has the advantage that we may choose the type of connection (system, session, remote). Additionally,
|
||||
|
||||
* when created **without** `dont_run_event_loop_thread_t` tag, the proxy **will start** a dedicated event loop thread on that connection;
|
||||
* or, when created **with** `dont_run_event_loop_thread_t` tag, the proxy will start **no** event loop thread on that connection.
|
||||
|
||||
* Or we don't care about connections at all (proxy factory overloads with no connection parameter). Under the hood, the proxy creates its own connection, to either the session bus (when in a user context) or the system bus otherwise. Additionally:
|
||||
* Or we don't care about connnections at all (proxy factory overloads with no connection parameter). Under the hood, the proxy creates its own connection, to either the session bus (when in a user context) or the system bus otherwise. Additionally:
|
||||
* when created **without** `dont_run_event_loop_thread_t` tag, the proxy **will start** a dedicated event loop thread on that connection;
|
||||
* or, when created **with** `dont_run_event_loop_thread_t` tag, the proxy will start **no** event loop thread on that connection.
|
||||
|
||||
A proxy needs an event loop if it's a "**long-lived**" proxy that listens on incoming messages like signals, async call replies, atc. Sharing one connection with its one event loop is more scalable. Starting a dedicated event loop in a proxy is simpler from API perspective, but comes at a performance and resource cost for each proxy creation/destruction, and it hurts scalability. A simple and scalable option are "**short-lived, light-weight**" proxies. Quite a typical use case is that we occasionally need to carry out one or a few D-Bus calls and that's it. We may create a proxy, do the calls, and let go of proxy. Such a light-weight proxy is created when `dont_run_event_loop_thread_t` tag is passed to the proxy factory (or with `createLightWeightProxy()`). Such a proxy **does not spawn** an event loop thread. It only support synchronous D-Bus calls (no signals, no async calls...), and is meant to be created, used right away, and then destroyed immediately.
|
||||
A proxy needs an event loop if it's a "**long-lived**" proxy that listens on incoming messages like signals, async call replies, atc. Sharing one connection with its one event loop is more scalable. Starting a dedicated event loop in a proxy is simpler from API perspective, but comes at a performance and resource cost for each proxy creation/destruction, and it hurts scalability. A simple and scalable option are "**short-lived, light-weight**" proxies. Quite a typical use case is that we occasionally need to carry out one or a few D-Bus calls and that's it. We may create a proxy, do the calls, and let go of proxy. Such a light-weight proxy is created when `dont_run_event_loop_thread_t` tag is passed to the proxy factory. Such a proxy **does not spawn** an event loop thread. It only support synchronous D-Bus calls (no signals, no async calls...), and is meant to be created, used right away, and then destroyed immediately.
|
||||
|
||||
#### Stopping internal I/O event loops graciously
|
||||
|
||||
@@ -508,19 +501,19 @@ The code written using this layer expresses in a declarative way *what* it does,
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create D-Bus connection to the (either system or session) bus and requests a well-known name on it.
|
||||
sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"};
|
||||
auto connection = sdbus::createBusConnection(serviceName);
|
||||
// Create D-Bus connection to the system bus and requests name on it.
|
||||
const char* serviceName = "org.sdbuscpp.concatenator";
|
||||
auto connection = sdbus::createSystemBusConnection(serviceName);
|
||||
|
||||
// Create concatenator D-Bus object.
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
auto concatenator = sdbus::createObject(*connection, std::move(objectPath));
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
auto concatenator = sdbus::createObject(*connection, objectPath);
|
||||
|
||||
auto concatenate = [&concatenator](const std::vector<int> numbers, const std::string& separator)
|
||||
{
|
||||
// Return error if there are no numbers in the collection
|
||||
if (numbers.empty())
|
||||
throw sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.Concatenator.Error"}, "No numbers provided");
|
||||
throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
|
||||
|
||||
std::string result;
|
||||
for (auto number : numbers)
|
||||
@@ -529,15 +522,17 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Emit 'concatenated' signal
|
||||
concatenator->emitSignal("concatenated").onInterface("org.sdbuscpp.Concatenator").withArguments(result);
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenator->emitSignal("concatenated").onInterface(interfaceName).withArguments(result);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Register D-Bus methods and signals on the concatenator object, and exports the object.
|
||||
concatenator->addVTable(sdbus::registerMethod("concatenate").implementedAs(std::move(concatenate)),
|
||||
sdbus::registerSignal("concatenated").withParameters<std::string>())
|
||||
.forInterface("org.sdbuscpp.Concatenator");
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenator->addVTable( sdbus::registerMethod("concatenate").implementedAs(std::move(concatenate))
|
||||
, sdbus::registerSignal{"concatenated").withParameters<std::string>() )
|
||||
.forInterface(interfaceName);
|
||||
|
||||
// Run the loop on the connection.
|
||||
connection->enterEventLoop();
|
||||
@@ -565,12 +560,12 @@ void onConcatenated(const std::string& concatenatedString)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create proxy object for the concatenator object on the server side
|
||||
sdbus::ServiceName destination{"org.sdbuscpp.concatenator"};
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
auto concatenatorProxy = sdbus::createProxy(std::move(destination), std::move(objectPath));
|
||||
const char* destinationName = "org.sdbuscpp.concatenator";
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
auto concatenatorProxy = sdbus::createProxy(destinationName, objectPath);
|
||||
|
||||
// Let's subscribe for the 'concatenated' signals
|
||||
sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([](const std::string& str){ onConcatenated(str); });
|
||||
|
||||
std::vector<int> numbers = {1, 2, 3};
|
||||
@@ -695,7 +690,7 @@ After running this through the code generator, we get the generated code that is
|
||||
|
||||
For each interface in the XML IDL file the generator creates one class that represents it. The class is de facto an interface which shall be implemented by the class inheriting it. The class' constructor takes care of registering all methods, signals and properties. For each D-Bus method there is a pure virtual member function. These pure virtual functions must be implemented in the child class. For each signal, there is a public function member that emits this signal.
|
||||
|
||||
Generated adaptor 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 adaptor classes support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
@@ -719,35 +714,30 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
|
||||
object_->registerSignal("concatenated").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
}
|
||||
|
||||
Concatenator_adaptor(const Concatenator_adaptor&) = delete;
|
||||
Concatenator_adaptor& operator=(const Concatenator_adaptor&) = delete;
|
||||
Concatenator_adaptor(Concatenator_adaptor&&) = delete;
|
||||
Concatenator_adaptor& operator=(Concatenator_adaptor&&) = delete;
|
||||
Concatenator_adaptor(Concatenator_adaptor&&) = default;
|
||||
Concatenator_adaptor& operator=(Concatenator_adaptor&&) = default;
|
||||
|
||||
~Concatenator_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerMethod("concatenate").withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); })
|
||||
, sdbus::registerSignal("concatenated").withParameters<std::string>("concatenatedString")
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
public:
|
||||
void emitConcatenated(const std::string& concatenatedString)
|
||||
{
|
||||
m_object.emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
object_->emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@@ -759,7 +749,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 support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
@@ -783,34 +773,30 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_->uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
|
||||
}
|
||||
|
||||
Concatenator_proxy(const Concatenator_proxy&) = delete;
|
||||
Concatenator_proxy& operator=(const Concatenator_proxy&) = delete;
|
||||
Concatenator_proxy(Concatenator_proxy&&) = delete;
|
||||
Concatenator_proxy& operator=(Concatenator_proxy&&) = delete;
|
||||
Concatenator_proxy(Concatenator_proxy&&) = default;
|
||||
Concatenator_proxy& operator=(Concatenator_proxy&&) = default;
|
||||
|
||||
~Concatenator_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
m_proxy.uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
|
||||
}
|
||||
|
||||
virtual void onConcatenated(const std::string& concatenatedString) = 0;
|
||||
|
||||
public:
|
||||
std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
m_proxy.callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
proxy_->callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@@ -839,7 +825,7 @@ Calling `registerAdaptor()` and `unregisterAdaptor()` was not necessary in previ
|
||||
class Concatenator : public sdbus::AdaptorInterfaces<org::sdbuscpp::Concatenator_adaptor /*, more adaptor classes if there are more interfaces*/>
|
||||
{
|
||||
public:
|
||||
Concatenator(sdbus::IConnection& connection, sdbus::ObjectPath objectPath)
|
||||
Concatenator(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
registerAdaptor();
|
||||
@@ -855,7 +841,7 @@ protected:
|
||||
{
|
||||
// Return error if there are no numbers in the collection
|
||||
if (numbers.empty())
|
||||
throw sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.Concatenator.Error"}, "No numbers provided");
|
||||
throw sdbus::Error("org.sdbuscpp.Concatenator.Error", "No numbers provided");
|
||||
|
||||
// Concatenate the numbers
|
||||
std::string result;
|
||||
@@ -882,13 +868,13 @@ That's it. We now have an implementation of a D-Bus object implementing `org.sdb
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create D-Bus connection to (either the system or session) bus and request a well-known name on it.
|
||||
sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"};
|
||||
auto connection = sdbus::createBusConnection(serviceName);
|
||||
// Create D-Bus connection to the system bus and requests name on it.
|
||||
const char* serviceName = "org.sdbuscpp.concatenator";
|
||||
auto connection = sdbus::createSystemBusConnection(serviceName);
|
||||
|
||||
// Create concatenator D-Bus object.
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
Concatenator concatenator(*connection, std::move(objectPath));
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
Concatenator concatenator(*connection, objectPath);
|
||||
|
||||
// Run the loop on the connection.
|
||||
connection->enterEventLoop();
|
||||
@@ -918,7 +904,7 @@ Calling `registerProxy()` and `unregisterProxy()` was not necessary in previous
|
||||
class ConcatenatorProxy : public sdbus::ProxyInterfaces<org::sdbuscpp::Concatenator_proxy /*, more proxy classes if there are more interfaces*/>
|
||||
{
|
||||
public:
|
||||
ConcatenatorProxy(sdbus::ServiceName destination, sdbus::ObjectPath objectPath)
|
||||
ConcatenatorProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
@@ -952,9 +938,9 @@ Now let's use this proxy to make remote calls and listen to signals in a real ap
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create proxy object for the concatenator object on the server side
|
||||
sdbus::ServiceName destination{"org.sdbuscpp.concatenator"};
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
|
||||
ConcatenatorProxy concatenatorProxy(std::move(destination), std::move(objectPath));
|
||||
const char* destinationName = "org.sdbuscpp.concatenator";
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
ConcatenatorProxy concatenatorProxy(destinationName, objectPath);
|
||||
|
||||
std::vector<int> numbers = {1, 2, 3};
|
||||
std::string separator = ":";
|
||||
@@ -1046,9 +1032,8 @@ void concatenate(sdbus::MethodCall call)
|
||||
reply.send();
|
||||
|
||||
// Emit 'concatenated' signal (creating and emitting signals is thread-safe)
|
||||
sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
|
||||
sdbus::SignalName signalName{"concatenated"};
|
||||
auto signal = g_concatenator->createSignal(interfaceName, signalName);
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
auto signal = g_concatenator->createSignal(interfaceName, "concatenated");
|
||||
signal << result;
|
||||
g_concatenator->emitSignal(signal);
|
||||
}).detach();
|
||||
@@ -1130,11 +1115,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, 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.
|
||||
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
|
||||
|
||||
### Lower-level API
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```c++
|
||||
int main(int argc, char *argv[])
|
||||
@@ -1157,7 +1142,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Invoke concatenate on given interface of the object
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << numbers << separator;
|
||||
concatenatorProxy->callMethod(method, callback);
|
||||
// When the reply comes, we shall get "Got concatenate result 1:2:3" on the standard output
|
||||
@@ -1165,7 +1150,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Invoke concatenate again, this time with no numbers and we shall get an error
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << std::vector<int>() << separator;
|
||||
concatenatorProxy->callMethod(method, callback);
|
||||
// When the reply comes, we shall get concatenation error message on the standard error output
|
||||
@@ -1187,7 +1172,7 @@ Another option is to use `std::future`-based overload of the `IProxy::callMethod
|
||||
...
|
||||
// Invoke concatenate on given interface of the object
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate);
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << numbers << separator;
|
||||
auto future = concatenatorProxy->callMethod(method, sdbus::with_future);
|
||||
try
|
||||
@@ -1204,18 +1189,6 @@ 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:
|
||||
@@ -1253,10 +1226,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
Empty `error` parameter means that no D-Bus error occurred while making the call, and subsequent arguments are valid D-Bus method return values. However, `error` parameter containing a value means that an error occurred during the call (and subsequent arguments are simply default-constructed), and the underlying `Error` instance provides us with the error name and message.
|
||||
|
||||
> **_Tip_:** The function returns the `sdbus::PendingAsyncCall` object, a non-owning, observing handle to the async call. It can be used to query whether the call is still in progress, and to cancel the call.
|
||||
|
||||
> **_Tip_:** There is also the `.uponReplyInvoke(callback, sdbus::return_slot);` variant with the `return_slot` tag, which returns `Slot` object, an owning RAII handle to the async call. This makes the client an owner of the pending async call. Letting go of the handle means cancelling the call.
|
||||
|
||||
Another option is to finish the async call statement with `getResultAsFuture()`, which is a template function which takes the list of types returned by the D-Bus method (empty list in case of `void`-returning method) which returns a `std::future` object, which will later, when the reply arrives, be set to contain the return value(s). Or if the call returns an error, `sdbus::Error` will be thrown by `std::future::get()`.
|
||||
|
||||
The future object will contain void for a void-returning D-Bus method, a single type for a single value returning D-Bus method, and a `std::tuple` to hold multiple return values of a D-Bus method.
|
||||
@@ -1276,18 +1245,6 @@ 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):
|
||||
@@ -1310,7 +1267,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, `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.
|
||||
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.
|
||||
|
||||
#### Generating callback-based async methods
|
||||
|
||||
@@ -1318,31 +1275,11 @@ 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()`.
|
||||
|
||||
#### 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).
|
||||
For a real example of a client-side asynchronous D-Bus methods, please look at sdbus-c++ [stress tests](/tests/stresstests).
|
||||
|
||||
## Method call timeout
|
||||
|
||||
@@ -1382,7 +1319,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 callback-based, future-based, or (with C++20) awaitable way, by calling `IProxy::getPropertyAsync()` method:
|
||||
Getting a property in asynchronous manner is also possible, in both callback-based and future-based way, by calling `IProxy::getPropertyAsync()` method:
|
||||
|
||||
```c++
|
||||
// Callback-based method:
|
||||
@@ -1391,15 +1328,10 @@ 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).
|
||||
@@ -1413,18 +1345,14 @@ uint32_t status = ...;
|
||||
proxy->setProperty("status").onInterface("org.sdbuscpp.Concatenator").toValue(status);
|
||||
```
|
||||
|
||||
Setting a property in asynchronous manner is also possible, in callback-based, future-based, or awaitable way, by calling `IProxy::setPropertyAsync()` method:
|
||||
Setting a property in asynchronous manner is also possible, in both callback-based and future-based 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,17 +1396,12 @@ class PropertyProvider_adaptor
|
||||
|
||||
public:
|
||||
PropertyProvider_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
|
||||
}
|
||||
|
||||
/*...*/
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerProperty("status").withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); })
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
~PropertyProvider_adaptor() = default;
|
||||
|
||||
private:
|
||||
// property getter
|
||||
@@ -1502,13 +1425,13 @@ public:
|
||||
// getting the property value
|
||||
uint32_t status()
|
||||
{
|
||||
return m_object.getProperty("status").onInterface(INTERFACE_NAME).get<uint32_t>();
|
||||
return object_->getProperty("status").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
// setting the property value
|
||||
void status(const uint32_t& value)
|
||||
{
|
||||
m_object.setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
object_->setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
/*...*/
|
||||
@@ -1521,7 +1444,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, 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.
|
||||
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.
|
||||
|
||||
The callback-based method will generate a pure virtual function `On<PropertyName>Property[Get|Set]Reply()`, which must be overridden by the derived class.
|
||||
|
||||
@@ -1555,13 +1478,13 @@ public:
|
||||
// getting the property value
|
||||
sdbus::PendingAsyncCall status()
|
||||
{
|
||||
return m_object.getPropertyAsync("status").onInterface(INTERFACE_NAME).uponReplyInvoke([this](std::optional<sdbus::Error> error, const sdbus::Variant& value){ this->onStatusPropertyGetReply(value.get<uint32_t>(), std::move(error)); });
|
||||
return object_->getPropertyAsync("status").onInterface(INTERFACE_NAME).uponReplyInvoke([this](std::optional<sdbus::Error> error, const sdbus::Variant& value){ this->onStatusPropertyGetReply(value.get<uint32_t>(), std::move(error)); });
|
||||
}
|
||||
|
||||
// setting the property value
|
||||
void status(const uint32_t& value)
|
||||
{
|
||||
m_object.setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
object_->setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
/*...*/
|
||||
@@ -1612,8 +1535,8 @@ sdbus-c++ provides many default, pre-defined C++ type representations for D-Bus
|
||||
| string-like, basic | 111 | o | OBJECT_PATH | `sdbus::ObjectPath` |
|
||||
| string-like, basic | 103 | g | SIGNATURE | `sdbus::Signature` |
|
||||
| container | 97 | a | ARRAY | `std::vector<T>`, `std::array<T>`, `std::span<T>` - if used as an array followed by a single complete type `T` <br /> `std::map<T1, T2>`, `std::unordered_map<T1, T2>` - if used as an array of dict entries |
|
||||
| container | 114,40,41 | r() | STRUCT | `sdbus::Struct<T1, T2, ...>` variadic class template |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant`, `std::variant<T1, ...>` |
|
||||
| container | 114,40,41 | r() | STRUCT | `sdbus::Struct<T1, T2, ...>` variadic class template |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant` |
|
||||
| container | 101,123,125 | e{} | DICT_ENTRY | - |
|
||||
| fixed, basic | 104 | h | UNIX_FD | `sdbus::UnixFd` |
|
||||
| reserved | 109 | m | (reserved) | - |
|
||||
@@ -1631,16 +1554,16 @@ To see how C++ types are mapped to D-Bus types (including container types) in sd
|
||||
|
||||
For more information on basic D-Bus types, D-Bus container types, and D-Bus type system in general, make sure to consult the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#type-system).
|
||||
|
||||
## Adding user-defined types to the sdbus-c++ type system
|
||||
### Extending sdbus-c++ type system
|
||||
|
||||
The above mapping between D-Bus and C++ types is what sdbus-c++ provides by default. However, the mapping can be extended. We can implement additional mapping between a D-Bus type and our custom type, i.e. teach sdbus-c++ to recognize and accept our own C++ types.
|
||||
The above mapping between D-Bus and C++ types is what sdbus-c++ provides by default. However, the mapping can be extended. You can implement additional mapping between a D-Bus type and their custom type.
|
||||
|
||||
We need two things to do that:
|
||||
|
||||
* implement `sdbus::Message` insertion (serialization) and extraction (deserialization) operators, so sdbus-c++ knows how to serialize/deserialize our custom type,
|
||||
* specialize `sdbus::signature_of` template for our custom type, so sdbus-c++ knows the mapping to D-Bus type and other necessary information about our type.
|
||||
|
||||
Say, we would like to represent D-Bus arrays as `std::list`s in our application. Since sdbus-c++ comes with pre-defined support for `std::vector`s, `std::array`s and `std::span`s as D-Bus array representations, we have to provide an extension. To implement message serialization and deserialization functions for `std::list`, we can simply copy the sdbus-c++ implementation of these functions for `std::vector`, and simply adjust for `std::list`. Then we provide `signature_of` specialization, again written in terms of one specialized for `std::vector`:
|
||||
Say, we would like to represent D-Bus arrays as `std::list`s in our application. Since sdbus-c++ comes with pre-defined support for `std::vector`s, `std::array`s and `std::span`s as D-Bus array representations, we have to provide an extension. To implement message serialization and deserialization functions for `std::list`, we can simply copy the sdbus-c++ implementation of these functions for `std::vector`, and simply adjust for `std::list`. Then we provide `signature_of` specialization, again written on terms of one specialized for `std::vector`:
|
||||
|
||||
```c++
|
||||
#include <list>
|
||||
@@ -1652,7 +1575,7 @@ namespace sdbus {
|
||||
template <typename _ElementType>
|
||||
sdbus::Message& operator<<(sdbus::Message& msg, const std::list<_ElementType>& items)
|
||||
{
|
||||
msg.openContainer<_ElementType>();
|
||||
msg.openContainer(sdbus::signature_of<_ElementType>::str());
|
||||
|
||||
for (const auto& item : items)
|
||||
msg << item;
|
||||
@@ -1666,7 +1589,7 @@ sdbus::Message& operator<<(sdbus::Message& msg, const std::list<_ElementType>& i
|
||||
template <typename _ElementType>
|
||||
sdbus::Message& operator>>(sdbus::Message& msg, std::list<_ElementType>& items)
|
||||
{
|
||||
if(!msg.enterContainer<_ElementType>())
|
||||
if(!msg.enterContainer(sdbus::signature_of<_ElementType>::str()))
|
||||
return msg;
|
||||
|
||||
while (true)
|
||||
@@ -1687,23 +1610,17 @@ sdbus::Message& operator>>(sdbus::Message& msg, std::list<_ElementType>& items)
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
// Implementing type traits for std::list -- we re-use by inheriting
|
||||
// from type traits already provided by sdbus-c++ for D-Bus arrays
|
||||
// Implementing type traits for std::list, and since we map it to D-Bus array,
|
||||
// we can re-use std::vector type traits because it's the same stuff.
|
||||
template <typename _Element, typename _Allocator>
|
||||
struct sdbus::signature_of<std::list<_Element, _Allocator>>
|
||||
: sdbus::signature_of<std::vector<_Element>>
|
||||
: sdbus::signature_of<std::vector<_Element, _Allocator>>
|
||||
{};
|
||||
```
|
||||
|
||||
Then we can simply use `std::list`s, serialize/deserialize them in a D-Bus message, in D-Bus method calls or return values... and they will be simply transmitted as D-Bus arrays.
|
||||
|
||||
Similarly, say we have our own `lockfree_map` which we would like to use natively with sdbus-c++ as a C++ type for D-Bus dictionary -- we can copy or build on top of `std::map` specializations.
|
||||
|
||||
### Teaching sdbus-c++ about user-defined structs
|
||||
|
||||
There is `SDBUSCPP_REGISTER_STRUCT` macro that we can use to teach sdbus-c++ about our structs and unlock some struct-related convenience functionality.
|
||||
|
||||
Say we have our custom type `my::Struct`:
|
||||
As another example, say we have our custom type `my::Struct` which we'd like to use as a D-Bus structure representation (sdbus-c++ provides `sdbus::Struct` type for that, but we don't want to use it because using our custom type directly is more convenient). Again, we have to provide type traits and message serialization/deserialization functions for our custom type. We build our functions and specializations on top of `sdbus::Struct`, so we don't have to copy and write a lot of boiler-plate. Serialization/deserialization functions can be placed in the same namespace as our custom type, and will be found thanks to the ADR lookup. The `signature_of` specialization must always be in either `sdbus` namespace or in a global namespace:
|
||||
|
||||
```c++
|
||||
namespace my {
|
||||
@@ -1713,101 +1630,30 @@ namespace my {
|
||||
std::string s;
|
||||
std::list<double> l;
|
||||
};
|
||||
|
||||
sdbus::Message& operator<<(sdbus::Message& msg, const Struct& items)
|
||||
{
|
||||
// Re-use sdbus::Struct functionality for simplicity -- view of my::Struct through sdbus::Struct with reference types
|
||||
return msg << sdbus::Struct{std::forward_as_tuple(items.i, items.s, items.l)};
|
||||
}
|
||||
|
||||
sdbus::Message& operator>>(sdbus::Message& msg, Struct& items)
|
||||
{
|
||||
// Re-use sdbus::Struct functionality for simplicity -- view of my::Struct through sdbus::Struct with reference types
|
||||
sdbus::Struct s{std::forward_as_tuple(items.i, items.s, items.l)};
|
||||
return msg >> s;
|
||||
}
|
||||
} // namespace my
|
||||
|
||||
template <>
|
||||
struct sdbus::signature_of<my::Struct>
|
||||
: sdbus::signature_of<sdbus::Struct<int, std::string, std::list<double>>>
|
||||
{};
|
||||
```
|
||||
|
||||
This is how we introduce the struct to sdbus-c++:
|
||||
> **_Note_:** One of `my::Struct` members is `std::list`. Thanks to the above custom support for `std::list`, it's now automatically accepted by sdbus-c++ as a D-Bus array representation.
|
||||
|
||||
```c++
|
||||
SDBUSCPP_REGISTER_STRUCT(my::Struct, i, s, l);
|
||||
```
|
||||
|
||||
The macro must be placed in the global namespace. The first argument is the struct type name and the remaining arguments are names of struct members. Of course, struct members must be of types supported by sdbus-c++ (or of user-defined types that sdbus-c++ was taught to recognize). This also means that members can be other structs -- provided that sdbus-c++ was taught about them with `SDBUSCPP_REGISTER_STRUCT` prior to this one.
|
||||
|
||||
`SDBUSCPP_REGISTER_STRUCT` enables us:
|
||||
|
||||
* to use user-defined structs in place of (more generic, less expressive) `sdbus::Struct`s
|
||||
* to serialize a user-defined struct as a dictionary of strings to variants (`a{sv}` dictionary)
|
||||
* to deserialize the `a{sv}` dictionary into a user-defined struct.
|
||||
|
||||
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)
|
||||
|
||||
> **_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.
|
||||
|
||||
### Using user-defined structs in place of `sdbus::Struct`
|
||||
|
||||
Many times, we have our own structs defined in our business logic code, and it would be very convenient to pass these structs directly to or from the sdbus-c++ IPC API where a D-Bus struct is expected, without having to translate them to or from `sdbus::Struct`.
|
||||
|
||||
For example, a D-Bus method `foo` that takes an argument of signature `(isad)` can simply be called with `my::Struct` instance instead of `sdbus::Struct<int, std::string, std::vector<dobule>>` instance:
|
||||
|
||||
```c++
|
||||
my::Struct s{77, "hello"s, {3.14, 285.9}};
|
||||
proxy->callMethod("foo").onInterface(INTERFACE_NAME).withArguments(s);
|
||||
```
|
||||
|
||||
For this purpose, the macro simply generates the `sdbus::Message` serialization and deserialization operators and the type traits (the `sdbus::signature_of` specialization) for `my::Struct`.
|
||||
|
||||
Nesting structs is supported by default.
|
||||
|
||||
### Serializing a user-defined struct as the a{sv} dictionary
|
||||
|
||||
`SDBUSCPP_REGISTER_STRUCT` macro additionally teaches sdbus-c++ to serialize our structs as `a{sv}` dictionaries. This can be quite a handy feature.
|
||||
|
||||
For example, a D-Bus method `foo` that takes an argument of signature `a{sv}` can be passed `my::Struct` instance:
|
||||
|
||||
```c++
|
||||
my::Struct s{77, "hello"s, {3.14, 285.9}};
|
||||
proxy->callMethod("foo").onInterface(INTERFACE_NAME).withArguments(sdbus::as_dictionary(s));
|
||||
```
|
||||
|
||||
Decorating the struct instance with `sdbus::as_dictionary()` instructs sdbus-c++ to serialize the struct as an `a{sv}` dictionary, with struct field name being the key and struct field value being the value. Here is a C++ representation of the resulting dictionary:
|
||||
|
||||
```c++
|
||||
std::map<std::string, sdbus::Variant> dict{{"i"s, sdbus::Variant{77}}, {"s"s, sdbus::Variant{"hello"s}}, {"l"s, sdbus::Variant{std::list<double>{3.14, 285.9}}}};
|
||||
```
|
||||
|
||||
The default struct-as-dict serialization strategy is single-level (as opposed to nested). Single-level means that struct members that are structs themselves are serialized as D-Bus structs (the variant in the dict entry contains a struct value). Nested means that also struct members that are structs are all serialized as an `a{sv}` dictionary (the variant in the dict entry contains `a{sv}` dictionary). We can turn on nested serialization with the `SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION` macro:
|
||||
|
||||
```c++
|
||||
SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(my::Struct);
|
||||
```
|
||||
|
||||
If nested strategy is also enabled for the nested struct type, then the same behavior applies for that struct, recursively. (It goes without saying that member struct type needs to be registered through `SDBUSCPP_REGISTER_STRUCT` macro, too.)
|
||||
|
||||
The macro must be placed before the `SDBUSCPP_REGISTER_STRUCT(my::Struct);` macro.
|
||||
|
||||
### Deserializing the a{sv} dictionary into a user-defined struct
|
||||
|
||||
Another handy feature enabled by the `SDBUSCPP_REGISTER_STRUCT` macro is an automatic deserialization of `a{sv}` dictionaries to user-defined structs.
|
||||
|
||||
For example, a D-Bus signal `bar` that carries data of signature `a{sv}` can be deserialized not only into a C++ dictionary type, but also directly into a user-defined struct, leading to shorter and more natural code:
|
||||
|
||||
```c++
|
||||
proxy->uponSignal("bar").onInterface(INTERFACE_NAME).call([](const my::Struct& s){ std::cout << "Got signal with s.i == " << s.i << "\n"; });
|
||||
```
|
||||
|
||||
How easy and convenient, right?
|
||||
|
||||
The requirements:
|
||||
|
||||
* All keys in the dictionary must exactly match the names of fields in the struct. Ordering of struct fields vs. items in the dictionary is irrelevant; the field in the struct is found by its name given by the dict key. If the corresponding struct field is not found, `sdbus::Error` exception is thrown.
|
||||
* The type of value in the dictionary item and the corresponding struct field must also exactly match. Otherwise, `sdbus::Error` exception is thrown.
|
||||
|
||||
The first bullet point is a so-called strict dict-to-struct deserialization strategy. There is also a relaxed one -- meaning that a dict entry key that does not have a matching struct member counterpart is not an error and is silently skipped. We can turn on relaxed deserialization with the `SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION` macro:
|
||||
|
||||
```c++
|
||||
SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(my::Struct);
|
||||
```
|
||||
|
||||
The macro must be placed before the `SDBUSCPP_REGISTER_STRUCT(my::Struct);` macro.
|
||||
|
||||
Real examples of extending sdbus-c++ types, including the use of all above-mentioned struct-related macros, can be found in [Message unit tests](/tests/unittests/Message_test.cpp) and also in test case [SdbusTestObject.CanSendAndReceiveDictionariesAsCustomStructsImplicitly](/tests/integrationtests/DBusMethodsTests.cpp#L266) in integration tests.
|
||||
|
||||
Happy `struct`ing!
|
||||
|
||||
> **_Wait!_:** You might say. What about XML IDL and generated C++ bindings? Well, there is no user-defined struct support in there. Yet. An extended XML syntax would be required. But we may implement something like that in the future (and you can help us).
|
||||
Live examples of extending sdbus-c++ types can be found in [Message unit tests](/tests/unittests/Message_test.cpp).
|
||||
|
||||
Support for match rules
|
||||
-----------------------
|
||||
@@ -1854,9 +1700,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
// We can now use connection objects in a familiar way, e.g. create adaptor and proxy objects on them, and exchange messages.
|
||||
// Here, using Concatenator IDL-generated bindings example from chapters above:
|
||||
Concatenator concatenator(*serverConnection, sdbus::ObjectPath{"/org/sdbuscpp/concatenator"});
|
||||
sdbus::ServiceName emptyDestination; // Destination may be empty in case of direct connections
|
||||
ConcatenatorProxy concatenatorProxy(*clientConnection, std::move(emptyDestination), sdbus::ObjectPath{"/org/sdbuscpp/concatenator"});
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
Concatenator concatenator(*serverConnection, objectPath);
|
||||
const char* emptyDestinationName = ""; // Destination may be empty in case of direct connections
|
||||
ConcatenatorProxy concatenatorProxy(*clientConnection, emptyDestinationName, objectPath);
|
||||
|
||||
// Perform call of concatenate D-Bus method
|
||||
std::vector<int> numbers = {1, 2, 3};
|
||||
@@ -1901,20 +1748,12 @@ sdbus-c++ v2 is a major release that comes with a number of breaking API/ABI/beh
|
||||
* Change in behavior: In *synchronous* D-Bus calls, the proxy object now keeps the connection instance blocked for the entire duration of the method call. Incoming messages like signals will be queued and processed after the call. Access to the connection from other threads is blocked. To avoid this (in case this hurts you):
|
||||
* either use short-lived, light-weight proxies for such synchronous calls,
|
||||
* or call the method in an asynchronous way.
|
||||
* Strong types were introduced for safer, less error-prone and more expressive API. What previously was `auto proxy = createProxy("org.sdbuscpp.concatenator", "/org/sdbuscpp/concatenator");` is now written like `auto proxy = createProxy(ServiceName{"org.sdbuscpp.concatenator"}, ObjectPath{"/org/sdbuscpp/concatenator"});`. These types are:
|
||||
* `ObjectPath` type for the object path (the type has been around already but now is also used consistently in sdbus-c++ API for object path strings)
|
||||
* `InterfaceName` type for D-Bus interface names
|
||||
* `BusName` (and its aliases `ServiceName` and `ConnectionName`) type for bus/service/connection names
|
||||
* `MemberName` (and its aliases `MethodName`, `SignalName` and `PropertyName`) type for D-Bus method, signal and property names
|
||||
* `Signature` type for the D-Bus signature (the type has been around already but now is also used consistently in sdbus-c++ API for signature strings)
|
||||
* `Error::Name` type for D-Bus error names
|
||||
* Signatures of callbacks `async_reply_handler`, `signal_handler`, `message_handler` and `property_set_callback` were modified to take input message objects by value instead of non-const ref to a message. The callback handler assumes ownership of the message. This API is cleaner and more self-explaining.
|
||||
* The `PollData` struct has been extended with a new data member: `eventFd`. All hooks with external event loops shall be modified to poll on this `eventFd` in addition to the `fd`.
|
||||
* `PollData::timeout_usec` was renamed to `PollData::timeout` and its type has been changed to `std::chrono::microseconds`. This member now holds directly what before had to be obtained through `PollData::getAbsoluteTimeout()` call.
|
||||
* `PollData::getRelativeTimeout()` return type was changed to `std::chrono::microseconds`.
|
||||
* `IConnection::processPendingRequest()` was renamed to `IConnection::processPendingEvent()`.
|
||||
* `Variant` constructor is now explicit.
|
||||
* `Variant`'s conversion operator to the underlying type is now explicit.
|
||||
* `IProxy::getCurrentlyProcessedMessage()` now returns `Message` by value instead of a raw pointer to it. The caller assumes ownership of the message.
|
||||
* Object D-Bus API registration is now done through `IObject::addVTable()` method. The vtable gets active immediately. No `finishRegistration()` call is needed anymore. vtables can be added and removed dynamically at run time. In addition to API simplification this brings consistency with sd-bus API and increases flexibility.
|
||||
* Subscription to signals has been simplified. The subscription is active right after the `registerSignalHandler`/`uponSignal()` call. No need for the final call to `finishRegistration()`.
|
||||
@@ -1925,21 +1764,13 @@ sdbus-c++ v2 is a major release that comes with a number of breaking API/ABI/beh
|
||||
* `AdaptorInterfaces::getObjectPath()` was removed. It can be replaced with `AdaptorInterfaces::getObject().getObjectPath()`.
|
||||
* `createConnection()` has been removed. To create a connection to the system bus use `createSystemConnection()` instead.
|
||||
* `createDefaultBusConnection()` has been renamed to `createBusConnection()`.
|
||||
* `IObject::removeObjectManager()` and `IObject::hasObjectManager()` were removed. Clients should now use the slot-returning `IObject::addObjectManager()` to control the `ObjectManager` interface lifetime.
|
||||
* `floating_slot_t` tag was removed from `IConnection::addObjectManager()`, the function is now by default floating-slot-based.
|
||||
* Slot-returning `IConnection::addMatch()` has gotten the `return_slot_t` tag parameter, while `floating_slot_t` was removed from the floating slot-based overload of the method.
|
||||
* Slot-returning `IConnection::addMatchAsync()` has gotten the `return_slot_t` tag parameter, while `floating_slot_t` was removed from the floating slot-based overload of the method.
|
||||
* Change in behavior: `Proxy`s now by default call `createBusConnection()` to get a connection when the connection is not provided explicitly by the caller, so they connect to either the session bus or the system bus depending on the context (as opposed to always to the system bus like before).
|
||||
* Callbacks taking `const sdbus::Error* error` were changed to take `std::optional<sdbus::Error>`, which better expresses the intent and meaning.
|
||||
* `getInterfaceName()`, `getMemberName()`, `getSender()`, `getPath()` and `getDestination()` methods of `Message` class now return `const char*` instead of `std::string`, for efficiency reasons.
|
||||
* `peekType()` method of `Message` class now returns a pair of `char` (type signature) and `const char*` (contents signature), for expressiveness and efficiency reasons.
|
||||
* D-Bus signatures when using high-level API are now assembled at compile time. There are breaking changes inside `signature_of` type traits and `Message` serialization/deserialization methods. This only interests you if you extend sdbus-c++ type system with your own types. See the updated tutorial on extending sdbus-c++ type system.
|
||||
* Generated adaptor and proxy classes are not moveable anymore.
|
||||
* Types and methods marked deprecated in sdbus-c++ v1 were removed completely.
|
||||
* CMake options got `SDBUSCPP_` prefix for better usability and minimal risk of conflicts in downstream CMake projects. `SDBUSCPP_INSTALL` CMake option was added.
|
||||
* CMake components got `sdbus-c++-` prefix.
|
||||
|
||||
An important note: **C++ bindings generated from XML files must be re-generated** with the new `sdbus-c++-xml2cpp` when migrating to sdbus-c++ v2.0.
|
||||
Some of these changes required correspoding adaptations in the sdbus-c++ codegen. Hence, your **C++ bindings (if any) must be re-generated** with the new sdbus-c++-xml2cpp v2 in order to use them with sdbus-c++ v2 API.
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
+2
-14
@@ -1,21 +1,9 @@
|
||||
# Building examples
|
||||
|
||||
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})
|
||||
add_executable(obj-manager-server org.freedesktop.DBus.ObjectManager/obj-manager-server.cpp)
|
||||
target_link_libraries(obj-manager-server sdbus-c++)
|
||||
|
||||
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})
|
||||
add_executable(obj-manager-client org.freedesktop.DBus.ObjectManager/obj-manager-client.cpp)
|
||||
target_link_libraries(obj-manager-client sdbus-c++)
|
||||
|
||||
if(SDBUSCPP_INSTALL)
|
||||
|
||||
+6
-6
@@ -21,14 +21,14 @@ public:
|
||||
|
||||
protected:
|
||||
Planet1_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Planet1_proxy(const Planet1_proxy&) = delete;
|
||||
Planet1_proxy& operator=(const Planet1_proxy&) = delete;
|
||||
Planet1_proxy(Planet1_proxy&&) = delete;
|
||||
Planet1_proxy& operator=(Planet1_proxy&&) = delete;
|
||||
Planet1_proxy(Planet1_proxy&&) = default;
|
||||
Planet1_proxy& operator=(Planet1_proxy&&) = default;
|
||||
|
||||
~Planet1_proxy() = default;
|
||||
|
||||
@@ -40,18 +40,18 @@ public:
|
||||
uint64_t GetPopulation()
|
||||
{
|
||||
uint64_t result;
|
||||
m_proxy.callMethod("GetPopulation").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("GetPopulation").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Name()
|
||||
{
|
||||
return m_proxy.getProperty("Name").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
return proxy_->getProperty("Name").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
+5
-5
@@ -21,20 +21,20 @@ public:
|
||||
|
||||
protected:
|
||||
Planet1_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
Planet1_adaptor(const Planet1_adaptor&) = delete;
|
||||
Planet1_adaptor& operator=(const Planet1_adaptor&) = delete;
|
||||
Planet1_adaptor(Planet1_adaptor&&) = delete;
|
||||
Planet1_adaptor& operator=(Planet1_adaptor&&) = delete;
|
||||
Planet1_adaptor(Planet1_adaptor&&) = default;
|
||||
Planet1_adaptor& operator=(Planet1_adaptor&&) = default;
|
||||
|
||||
~Planet1_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerMethod("GetPopulation").withOutputParamNames("population").implementedAs([this](){ return this->GetPopulation(); })
|
||||
object_->addVTable( sdbus::registerMethod("GetPopulation").withOutputParamNames("population").implementedAs([this](){ return this->GetPopulation(); })
|
||||
, sdbus::registerProperty("Name").withGetter([this](){ return this->Name(); })
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ private:
|
||||
virtual std::string Name() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
@@ -12,48 +12,34 @@
|
||||
#include "examplemanager-planet1-client-glue.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
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))
|
||||
PlanetProxy(sdbus::IConnection& connection, std::string destination, std::string 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();
|
||||
}
|
||||
};
|
||||
|
||||
class ManagerProxy final : public sdbus::ProxyInterfaces<sdbus::ObjectManager_proxy>
|
||||
class ManagerProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
|
||||
{
|
||||
public:
|
||||
ManagerProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath path)
|
||||
: ProxyInterfaces(connection, destination, std::move(path))
|
||||
, m_connection(connection)
|
||||
, m_destination(std::move(destination))
|
||||
ManagerProxy(sdbus::IConnection& connection, const std::string& destination, std::string path)
|
||||
: ProxyInterfaces(connection, destination, std::move(path))
|
||||
, m_connection(connection)
|
||||
, m_destination(destination)
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
ManagerProxy(const ManagerProxy&) = delete;
|
||||
ManagerProxy& operator=(const ManagerProxy&) = delete;
|
||||
ManagerProxy(ManagerProxy&&) = delete;
|
||||
ManagerProxy& operator=(ManagerProxy&&) = delete;
|
||||
|
||||
~ManagerProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
@@ -61,7 +47,8 @@ public:
|
||||
|
||||
void handleExistingObjects()
|
||||
{
|
||||
auto objectsInterfacesAndProperties = GetManagedObjects();
|
||||
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
|
||||
objectsInterfacesAndProperties = GetManagedObjects();
|
||||
for (const auto& [object, interfacesAndProperties] : objectsInterfacesAndProperties) {
|
||||
onInterfacesAdded(object, interfacesAndProperties);
|
||||
}
|
||||
@@ -69,57 +56,55 @@ public:
|
||||
|
||||
private:
|
||||
void onInterfacesAdded( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>& interfacesAndProperties) override
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
|
||||
{
|
||||
std::cout << objectPath << " added:\t";
|
||||
for (const auto& [interface, _] : interfacesAndProperties) {
|
||||
std::cout << interface << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
std::cout << std::endl;
|
||||
|
||||
// Parse and print some more info
|
||||
auto planetInterface = interfacesAndProperties.find(sdbus::InterfaceName{org::sdbuscpp::ExampleManager::Planet1_proxy::INTERFACE_NAME});
|
||||
auto planetInterface = interfacesAndProperties.find(org::sdbuscpp::ExampleManager::Planet1_proxy::INTERFACE_NAME);
|
||||
if (planetInterface == interfacesAndProperties.end()) {
|
||||
return;
|
||||
}
|
||||
const auto& properties = planetInterface->second;
|
||||
// get a property which was passed as part of the signal.
|
||||
const auto& name = properties.at(sdbus::PropertyName{"Name"}).get<std::string>();
|
||||
const auto& name = properties.at("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" << '\n';
|
||||
std::cout << name << " has a population of " << planet.GetPopulation() << ".\n" << std::endl;
|
||||
}
|
||||
|
||||
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<sdbus::InterfaceName>& interfaces) override
|
||||
, const std::vector<std::string>& interfaces) override
|
||||
{
|
||||
std::cout << objectPath << " removed:\t";
|
||||
for (const auto& interface : interfaces) {
|
||||
std::cout << interface << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
sdbus::IConnection& m_connection;
|
||||
sdbus::ServiceName m_destination;
|
||||
std::string m_destination;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
auto connection = sdbus::createSessionBusConnection();
|
||||
|
||||
sdbus::ServiceName destination{"org.sdbuscpp.examplemanager"};
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/examplemanager"};
|
||||
auto managerProxy = std::make_unique<ManagerProxy>(*connection, std::move(destination), std::move(objectPath));
|
||||
auto managerProxy = std::make_unique<ManagerProxy>(*connection, "org.sdbuscpp.examplemanager", "/org/sdbuscpp/examplemanager");
|
||||
try {
|
||||
managerProxy->handleExistingObjects();
|
||||
}
|
||||
catch (const sdbus::Error& e) {
|
||||
if (e.getName() == "org.freedesktop.DBus.Error.ServiceUnknown") {
|
||||
std::cout << "Waiting for server to start ..." << '\n';
|
||||
std::cout << "Waiting for server to start ..." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
connection->enterEventLoop();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -18,24 +18,16 @@
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
class ManagerAdaptor : public sdbus::AdaptorInterfaces<sdbus::ObjectManager_adaptor>
|
||||
{
|
||||
public:
|
||||
ManagerAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path)
|
||||
ManagerAdaptor(sdbus::IConnection& connection, std::string path)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
ManagerAdaptor(const ManagerAdaptor&) = delete;
|
||||
ManagerAdaptor& operator=(const ManagerAdaptor&) = delete;
|
||||
ManagerAdaptor(ManagerAdaptor&&) = delete;
|
||||
ManagerAdaptor& operator=(ManagerAdaptor&&) = delete;
|
||||
|
||||
~ManagerAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
@@ -47,23 +39,18 @@ class PlanetAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::Exam
|
||||
, sdbus::Properties_adaptor >
|
||||
{
|
||||
public:
|
||||
PlanetAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path, std::string name, uint64_t population)
|
||||
PlanetAdaptor(sdbus::IConnection& connection, std::string path, std::string name, uint64_t population)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
, m_name(std::move(name))
|
||||
, m_population(population)
|
||||
{
|
||||
registerAdaptor();
|
||||
emitInterfacesAddedSignal({sdbus::InterfaceName{Planet1_adaptor::INTERFACE_NAME}});
|
||||
emitInterfacesAddedSignal({org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME});
|
||||
}
|
||||
|
||||
PlanetAdaptor(const PlanetAdaptor&) = delete;
|
||||
PlanetAdaptor& operator=(const PlanetAdaptor&) = delete;
|
||||
PlanetAdaptor(PlanetAdaptor&&) = delete;
|
||||
PlanetAdaptor& operator=(PlanetAdaptor&&) = delete;
|
||||
|
||||
~PlanetAdaptor()
|
||||
{
|
||||
emitInterfacesRemovedSignal({sdbus::InterfaceName{Planet1_adaptor::INTERFACE_NAME}});
|
||||
emitInterfacesRemovedSignal({org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME});
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
@@ -89,26 +76,24 @@ void printCountDown(const std::string& message, int seconds)
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
std::cout << i << " " << std::flush;
|
||||
}
|
||||
std::cout << '\n';
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
auto connection = sdbus::createSessionBusConnection();
|
||||
const sdbus::ServiceName serviceName{"org.sdbuscpp.examplemanager"};
|
||||
connection->requestName(serviceName);
|
||||
connection->requestName("org.sdbuscpp.examplemanager");
|
||||
connection->enterEventLoopAsync();
|
||||
|
||||
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
|
||||
auto manager = std::make_unique<ManagerAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager"});
|
||||
auto manager = std::make_unique<ManagerAdaptor>(*connection, "/org/sdbuscpp/examplemanager");
|
||||
while (true)
|
||||
{
|
||||
printCountDown("Creating PlanetAdaptor in ", 5);
|
||||
auto earth = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Earth"}, "Earth", 7'874'965'825);
|
||||
auto earth = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Earth", "Earth", 7'874'965'825);
|
||||
printCountDown("Creating PlanetAdaptor in ", 5);
|
||||
auto trantor = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Trantor"}, "Trantor", 40'000'000'000);
|
||||
auto trantor = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Trantor", "Trantor", 40'000'000'000);
|
||||
printCountDown("Creating PlanetAdaptor in ", 5);
|
||||
auto laconia = std::make_unique<PlanetAdaptor>(*connection, sdbus::ObjectPath{"/org/sdbuscpp/examplemanager/Planet1/Laconia"}, "Laconia", 231'721);
|
||||
auto laconia = std::make_unique<PlanetAdaptor>(*connection, "/org/sdbuscpp/examplemanager/Planet1/Laconia", "Laconia", 231'721);
|
||||
printCountDown("Removing PlanetAdaptor in ", 5);
|
||||
earth.reset();
|
||||
printCountDown("Removing PlanetAdaptor in ", 5);
|
||||
@@ -117,7 +102,7 @@ int main()
|
||||
laconia.reset();
|
||||
}
|
||||
|
||||
connection->releaseName(serviceName);
|
||||
connection->releaseName("org.sdbuscpp.examplemanager");
|
||||
connection->leaveEventLoop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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:
|
||||
explicit ObjectHolder(std::unique_ptr<IObject>&& object)
|
||||
ObjectHolder(std::unique_ptr<IObject>&& object)
|
||||
: object_(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] const IObject& getObject() const
|
||||
const IObject& getObject() const
|
||||
{
|
||||
assert(object_ != nullptr);
|
||||
return *object_;
|
||||
}
|
||||
|
||||
[[nodiscard]] IObject& getObject()
|
||||
IObject& getObject()
|
||||
{
|
||||
assert(object_ != nullptr);
|
||||
return *object_;
|
||||
@@ -88,17 +88,12 @@ 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
|
||||
*
|
||||
@@ -107,9 +102,9 @@ namespace sdbus {
|
||||
*
|
||||
* For more information, consult @ref createObject(sdbus::IConnection&,std::string)
|
||||
*/
|
||||
AdaptorInterfaces(IConnection& connection, ObjectPath objectPath)
|
||||
AdaptorInterfaces(IConnection& connection, std::string objectPath)
|
||||
: ObjectHolder(createObject(connection, std::move(objectPath)))
|
||||
, Interfaces(getObject())...
|
||||
, _Interfaces(getObject())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -122,11 +117,11 @@ namespace sdbus {
|
||||
*/
|
||||
void registerAdaptor()
|
||||
{
|
||||
(Interfaces::registerAdaptor(), ...);
|
||||
(_Interfaces::registerAdaptor(), ...);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Unregisters adaptor's API and removes it from the bus
|
||||
* @brief Unregisters adaptors's API and removes it from the bus
|
||||
*
|
||||
* This function must be called in the destructor of the final adaptor class that implements AdaptorInterfaces.
|
||||
*
|
||||
@@ -145,9 +140,13 @@ namespace sdbus {
|
||||
protected:
|
||||
using base_type = AdaptorInterfaces;
|
||||
|
||||
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces(AdaptorInterfaces&&) = default;
|
||||
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = default;
|
||||
~AdaptorInterfaces() = default;
|
||||
};
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_ADAPTORINTERFACES_H_ */
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* (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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ConvenienceApiClasses.h
|
||||
*
|
||||
@@ -27,7 +27,6 @@
|
||||
#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>
|
||||
@@ -38,7 +37,6 @@
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
@@ -47,47 +45,34 @@ namespace sdbus {
|
||||
class IProxy;
|
||||
class Error;
|
||||
class PendingAsyncCall;
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
class VTableAdder
|
||||
{
|
||||
public:
|
||||
void forInterface(InterfaceName interfaceName);
|
||||
VTableAdder(IObject& object, std::vector<VTableItem> vtable);
|
||||
void forInterface(std::string interfaceName);
|
||||
[[nodiscard]] Slot forInterface(InterfaceName interfaceName, return_slot_t);
|
||||
[[nodiscard]] Slot forInterface(std::string interfaceName, return_slot_t);
|
||||
|
||||
private:
|
||||
friend IObject;
|
||||
VTableAdder(IObject& object, std::vector<VTableItem> vtable);
|
||||
|
||||
IObject& object_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
IObject& object_;
|
||||
std::vector<VTableItem> vtable_;
|
||||
};
|
||||
|
||||
class SignalEmitter
|
||||
{
|
||||
public:
|
||||
SignalEmitter& onInterface(const InterfaceName& interfaceName);
|
||||
SignalEmitter& onInterface(const std::string& interfaceName);
|
||||
SignalEmitter& onInterface(const char* interfaceName);
|
||||
template <typename... Args> void withArguments(Args&&... args);
|
||||
|
||||
SignalEmitter(const SignalEmitter&) = delete;
|
||||
SignalEmitter& operator=(const SignalEmitter&) = delete;
|
||||
SignalEmitter(IObject& object, const std::string& signalName);
|
||||
SignalEmitter(SignalEmitter&& other) = default;
|
||||
SignalEmitter& operator=(SignalEmitter&&) = delete;
|
||||
~SignalEmitter() noexcept(false);
|
||||
SignalEmitter& onInterface(const std::string& interfaceName);
|
||||
template <typename... _Args> void withArguments(_Args&&... args);
|
||||
|
||||
private:
|
||||
friend IObject;
|
||||
SignalEmitter(IObject& object, const SignalName& signalName);
|
||||
SignalEmitter(IObject& object, const char* signalName);
|
||||
|
||||
IObject& object_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const char* signalName_;
|
||||
IObject& object_;
|
||||
const std::string& signalName_;
|
||||
Signal signal_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed
|
||||
};
|
||||
@@ -95,29 +80,22 @@ namespace sdbus {
|
||||
class MethodInvoker
|
||||
{
|
||||
public:
|
||||
MethodInvoker& onInterface(const InterfaceName& interfaceName);
|
||||
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);
|
||||
void dontExpectReply();
|
||||
|
||||
MethodInvoker(const MethodInvoker&) = delete;
|
||||
MethodInvoker& operator=(const MethodInvoker&) = delete;
|
||||
MethodInvoker(IProxy& proxy, const std::string& methodName);
|
||||
MethodInvoker(MethodInvoker&& other) = default;
|
||||
MethodInvoker& operator=(MethodInvoker&&) = delete;
|
||||
~MethodInvoker() noexcept(false);
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
MethodInvoker(IProxy& proxy, const MethodName& methodName);
|
||||
MethodInvoker(IProxy& proxy, const char* methodName);
|
||||
MethodInvoker& onInterface(const std::string& 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);
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const char* methodName_;
|
||||
void dontExpectReply();
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& methodName_;
|
||||
uint64_t timeout_{};
|
||||
MethodCall method_;
|
||||
int exceptions_{}; // Number of active exceptions when MethodInvoker is constructed
|
||||
@@ -127,29 +105,21 @@ namespace sdbus {
|
||||
class AsyncMethodInvoker
|
||||
{
|
||||
public:
|
||||
AsyncMethodInvoker& onInterface(const InterfaceName& interfaceName);
|
||||
AsyncMethodInvoker(IProxy& proxy, const std::string& methodName);
|
||||
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);
|
||||
// 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> Awaitable<awaitable_return_t<Args...>> getResultAsAwaitable();
|
||||
template <typename... _Args> std::future<future_return_t<_Args...>> getResultAsFuture();
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
AsyncMethodInvoker(IProxy& proxy, const MethodName& methodName);
|
||||
AsyncMethodInvoker(IProxy& proxy, const char* methodName);
|
||||
template <typename Function> async_reply_handler makeAsyncReplyHandler(Function&& callback);
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const char* methodName_;
|
||||
IProxy& proxy_;
|
||||
const std::string& methodName_;
|
||||
uint64_t timeout_{};
|
||||
MethodCall method_;
|
||||
};
|
||||
@@ -157,132 +127,99 @@ namespace sdbus {
|
||||
class SignalSubscriber
|
||||
{
|
||||
public:
|
||||
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);
|
||||
SignalSubscriber(IProxy& proxy, const std::string& signalName);
|
||||
SignalSubscriber& onInterface(std::string interfaceName);
|
||||
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);
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const char* signalName_;
|
||||
const char* interfaceName_{};
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& signalName_;
|
||||
std::string interfaceName_;
|
||||
};
|
||||
|
||||
class PropertyGetter
|
||||
{
|
||||
public:
|
||||
Variant onInterface(std::string_view interfaceName);
|
||||
PropertyGetter(IProxy& proxy, const std::string& propertyName);
|
||||
Variant onInterface(const std::string& interfaceName);
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
PropertyGetter(IProxy& proxy, std::string_view propertyName);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::string_view propertyName_;
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
};
|
||||
|
||||
class AsyncPropertyGetter
|
||||
{
|
||||
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);
|
||||
AsyncPropertyGetter(IProxy& proxy, const std::string& propertyName);
|
||||
AsyncPropertyGetter& onInterface(const std::string& interfaceName);
|
||||
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
|
||||
std::future<Variant> getResultAsFuture();
|
||||
Awaitable<Variant> getResultAsAwaitable();
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
AsyncPropertyGetter(IProxy& proxy, std::string_view propertyName);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::string_view propertyName_;
|
||||
std::string_view interfaceName_;
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
const std::string* interfaceName_{};
|
||||
};
|
||||
|
||||
class PropertySetter
|
||||
{
|
||||
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);
|
||||
PropertySetter(IProxy& proxy, const std::string& propertyName);
|
||||
PropertySetter& onInterface(const std::string& interfaceName);
|
||||
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);
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
PropertySetter(IProxy& proxy, std::string_view propertyName);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::string_view propertyName_;
|
||||
std::string_view interfaceName_;
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
const std::string* interfaceName_{};
|
||||
};
|
||||
|
||||
class AsyncPropertySetter
|
||||
{
|
||||
public:
|
||||
AsyncPropertySetter& onInterface(std::string_view interfaceName);
|
||||
template <typename Value> AsyncPropertySetter& toValue(Value&& value);
|
||||
AsyncPropertySetter(IProxy& proxy, const std::string& propertyName);
|
||||
AsyncPropertySetter& onInterface(const std::string& interfaceName);
|
||||
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);
|
||||
std::future<void> getResultAsFuture();
|
||||
Awaitable<void> getResultAsAwaitable();
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
AsyncPropertySetter(IProxy& proxy, std::string_view propertyName);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::string_view propertyName_;
|
||||
std::string_view interfaceName_;
|
||||
IProxy& proxy_;
|
||||
const std::string& propertyName_;
|
||||
const std::string* interfaceName_{};
|
||||
Variant value_;
|
||||
};
|
||||
|
||||
class AllPropertiesGetter
|
||||
{
|
||||
public:
|
||||
std::map<PropertyName, Variant> onInterface(std::string_view interfaceName);
|
||||
AllPropertiesGetter(IProxy& proxy);
|
||||
std::map<std::string, Variant> onInterface(const std::string& interfaceName);
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
explicit AllPropertiesGetter(IProxy& proxy);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
IProxy& proxy_;
|
||||
};
|
||||
|
||||
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);
|
||||
std::future<std::map<PropertyName, Variant>> getResultAsFuture();
|
||||
Awaitable<std::map<PropertyName, Variant>> getResultAsAwaitable();
|
||||
AsyncAllPropertiesGetter(IProxy& proxy);
|
||||
AsyncAllPropertiesGetter& onInterface(const std::string& interfaceName);
|
||||
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
|
||||
std::future<std::map<std::string, Variant>> getResultAsFuture();
|
||||
|
||||
private:
|
||||
friend IProxy;
|
||||
explicit AsyncAllPropertiesGetter(IProxy& proxy);
|
||||
|
||||
static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
IProxy& proxy_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::string_view interfaceName_;
|
||||
IProxy& proxy_;
|
||||
const std::string* interfaceName_{};
|
||||
};
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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> // NOLINT(misc-header-include-cycle)
|
||||
#include <sdbus-c++/IProxy.h> // NOLINT(misc-header-include-cycle)
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
@@ -53,36 +53,21 @@ namespace sdbus {
|
||||
{
|
||||
}
|
||||
|
||||
inline void VTableAdder::forInterface(InterfaceName interfaceName)
|
||||
inline void VTableAdder::forInterface(std::string interfaceName)
|
||||
{
|
||||
object_.addVTable(std::move(interfaceName), std::move(vtable_));
|
||||
}
|
||||
|
||||
inline void VTableAdder::forInterface(std::string interfaceName)
|
||||
{
|
||||
forInterface(InterfaceName{std::move(interfaceName)});
|
||||
}
|
||||
|
||||
[[nodiscard]] inline Slot VTableAdder::forInterface(InterfaceName interfaceName, return_slot_t)
|
||||
{
|
||||
return object_.addVTable(std::move(interfaceName), std::move(vtable_), return_slot);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline Slot VTableAdder::forInterface(std::string interfaceName, return_slot_t)
|
||||
{
|
||||
return forInterface(InterfaceName{std::move(interfaceName)}, return_slot);
|
||||
return object_.addVTable(std::move(interfaceName), std::move(vtable_), return_slot);
|
||||
}
|
||||
|
||||
/*** ------------- ***/
|
||||
/*** SignalEmitter ***/
|
||||
/*** ------------- ***/
|
||||
|
||||
inline SignalEmitter::SignalEmitter(IObject& object, const SignalName& signalName)
|
||||
: SignalEmitter(object, signalName.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalEmitter::SignalEmitter(IObject& object, const char* signalName)
|
||||
inline SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName)
|
||||
: object_(object)
|
||||
, signalName_(signalName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
@@ -107,41 +92,26 @@ namespace sdbus {
|
||||
object_.emitSignal(signal_);
|
||||
}
|
||||
|
||||
inline SignalEmitter& SignalEmitter::onInterface(const InterfaceName& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline SignalEmitter& SignalEmitter::onInterface(const char* interfaceName)
|
||||
{
|
||||
signal_ = object_.createSignal(interfaceName, signalName_);
|
||||
|
||||
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)...);
|
||||
}
|
||||
|
||||
/*** ------------- ***/
|
||||
/*** MethodInvoker ***/
|
||||
/*** ------------- ***/
|
||||
|
||||
inline MethodInvoker::MethodInvoker(IProxy& proxy, const MethodName& methodName)
|
||||
: MethodInvoker(proxy, methodName.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
inline MethodInvoker::MethodInvoker(IProxy& proxy, const char* methodName)
|
||||
inline MethodInvoker::MethodInvoker(IProxy& proxy, const std::string& methodName)
|
||||
: proxy_(proxy)
|
||||
, methodName_(methodName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
@@ -167,17 +137,7 @@ namespace sdbus {
|
||||
proxy_.callMethod(method_, timeout_);
|
||||
}
|
||||
|
||||
inline MethodInvoker& MethodInvoker::onInterface(const InterfaceName& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline MethodInvoker& MethodInvoker::onInterface(const char* interfaceName)
|
||||
{
|
||||
method_ = proxy_.createMethodCall(interfaceName, methodName_);
|
||||
|
||||
@@ -191,25 +151,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
|
||||
|
||||
@@ -230,28 +190,13 @@ namespace sdbus {
|
||||
/*** AsyncMethodInvoker ***/
|
||||
/*** ------------------ ***/
|
||||
|
||||
inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const MethodName& methodName)
|
||||
: AsyncMethodInvoker(proxy, methodName.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const char* methodName)
|
||||
inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const std::string& methodName)
|
||||
: proxy_(proxy)
|
||||
, methodName_(methodName)
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const InterfaceName& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const char* interfaceName)
|
||||
{
|
||||
method_ = proxy_.createMethodCall(interfaceName, methodName_);
|
||||
|
||||
@@ -265,50 +210,33 @@ 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_);
|
||||
}
|
||||
|
||||
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))
|
||||
, timeout_
|
||||
, return_slot );
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(Function&& callback)
|
||||
{
|
||||
return [callback = std::forward<Function>(callback)](MethodReply reply, std::optional<Error> error)
|
||||
auto asyncReplyHandler = [callback = std::forward<_Function>(callback)](MethodReply reply, std::optional<Error> error)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<Function> args;
|
||||
tuple_of_function_input_arg_types_t<_Function> args;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple (if no error occurred).
|
||||
if (!error)
|
||||
@@ -329,18 +257,20 @@ namespace sdbus {
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
sdbus::apply(callback, std::move(error), args);
|
||||
};
|
||||
|
||||
return proxy_.callMethodAsync(method_, std::move(asyncReplyHandler), timeout_);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::future<future_return_t<Args...>> AsyncMethodInvoker::getResultAsFuture()
|
||||
template <typename... _Args>
|
||||
std::future<future_return_t<_Args...>> AsyncMethodInvoker::getResultAsFuture()
|
||||
{
|
||||
auto promise = std::make_shared<std::promise<future_return_t<Args...>>>();
|
||||
auto promise = std::make_shared<std::promise<future_return_t<_Args...>>>();
|
||||
auto future = promise->get_future();
|
||||
|
||||
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, Args... args)
|
||||
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, _Args... args)
|
||||
{
|
||||
if (!error)
|
||||
if constexpr (!std::is_void_v<future_return_t<Args...>>)
|
||||
if constexpr (!std::is_void_v<future_return_t<_Args...>>)
|
||||
promise->set_value({std::move(args)...});
|
||||
else
|
||||
promise->set_value();
|
||||
@@ -354,106 +284,65 @@ 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 ***/
|
||||
/*** ---------------- ***/
|
||||
|
||||
inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const SignalName& signalName)
|
||||
: SignalSubscriber(proxy, signalName.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const char* signalName)
|
||||
inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const std::string& signalName)
|
||||
: proxy_(proxy)
|
||||
, signalName_(signalName)
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalSubscriber& SignalSubscriber::onInterface(const InterfaceName& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline SignalSubscriber& SignalSubscriber::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
return onInterface(interfaceName.c_str());
|
||||
}
|
||||
|
||||
inline SignalSubscriber& SignalSubscriber::onInterface(const char* interfaceName)
|
||||
inline SignalSubscriber& SignalSubscriber::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
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
|
||||
assert(!interfaceName_.empty()); // 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
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.registerSignalHandler( interfaceName_
|
||||
, signalName_
|
||||
, makeSignalHandler(std::forward<Function>(callback))
|
||||
, makeSignalHandler(std::forward<_Function>(callback))
|
||||
, return_slot );
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline signal_handler SignalSubscriber::makeSignalHandler(Function&& callback)
|
||||
template <typename _Function>
|
||||
inline signal_handler SignalSubscriber::makeSignalHandler(_Function&& callback)
|
||||
{
|
||||
return [callback = std::forward<Function>(callback)](Signal signal)
|
||||
return [callback = std::forward<_Function>(callback)](Signal signal)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the signal message.
|
||||
tuple_of_function_input_arg_types_t<Function> signalArgs;
|
||||
tuple_of_function_input_arg_types_t<_Function> signalArgs;
|
||||
|
||||
// The signal handler can take pure signal parameters only, or an additional `std::optional<Error>` as its first
|
||||
// parameter. In the former case, if the deserialization fails (e.g. due to signature mismatch),
|
||||
// the failure is ignored (and signal simply dropped). In the latter case, the deserialization failure
|
||||
// will be communicated to the client's signal handler as a valid Error object inside the std::optional parameter.
|
||||
if constexpr (has_error_param_v<Function>)
|
||||
if constexpr (has_error_param_v<_Function>)
|
||||
{
|
||||
// Deserialize input arguments from the signal message into the tuple
|
||||
try
|
||||
{
|
||||
signal >> signalArgs;
|
||||
}
|
||||
catch (const Error& e)
|
||||
catch (const sdbus::Error& e)
|
||||
{
|
||||
// Pass message deserialization exceptions to the client via callback error parameter,
|
||||
// instead of propagating them up the message loop call stack.
|
||||
@@ -479,17 +368,17 @@ namespace sdbus {
|
||||
/*** PropertyGetter ***/
|
||||
/*** -------------- ***/
|
||||
|
||||
inline PropertyGetter::PropertyGetter(IProxy& proxy, std::string_view propertyName)
|
||||
inline PropertyGetter::PropertyGetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(std::move(propertyName))
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline Variant PropertyGetter::onInterface(std::string_view interfaceName)
|
||||
inline Variant PropertyGetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
Variant var;
|
||||
proxy_.callMethod("Get")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(interfaceName, propertyName_)
|
||||
.storeResultsTo(var);
|
||||
return var;
|
||||
@@ -499,136 +388,111 @@ namespace sdbus {
|
||||
/*** AsyncPropertyGetter ***/
|
||||
/*** ------------------- ***/
|
||||
|
||||
inline AsyncPropertyGetter::AsyncPropertyGetter(IProxy& proxy, std::string_view propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(std::move(propertyName))
|
||||
inline AsyncPropertyGetter::AsyncPropertyGetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncPropertyGetter& AsyncPropertyGetter::onInterface(std::string_view interfaceName)
|
||||
inline AsyncPropertyGetter& AsyncPropertyGetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
interfaceName_ = &interfaceName;
|
||||
|
||||
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>
|
||||
, "Property get callback function must accept std::optional<Error> and property value as 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
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("Get")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_)
|
||||
.uponReplyInvoke(std::forward<Function>(callback));
|
||||
}
|
||||
|
||||
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>
|
||||
, "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
|
||||
|
||||
return proxy_.callMethodAsync("Get")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_)
|
||||
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_)
|
||||
.uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
inline std::future<Variant> AsyncPropertyGetter::getResultAsFuture()
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("Get")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_)
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_)
|
||||
.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 ***/
|
||||
/*** -------------- ***/
|
||||
|
||||
inline PropertySetter::PropertySetter(IProxy& proxy, std::string_view propertyName)
|
||||
inline PropertySetter::PropertySetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(std::move(propertyName))
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline PropertySetter& PropertySetter::onInterface(std::string_view interfaceName)
|
||||
inline PropertySetter& PropertySetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
interfaceName_ = &interfaceName;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline void PropertySetter::toValue(const Variant& value)
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
proxy_.callMethod("Set")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_, value);
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_, value);
|
||||
}
|
||||
|
||||
inline void PropertySetter::toValue(const Variant& value, dont_expect_reply_t)
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
proxy_.callMethod("Set")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_, value)
|
||||
.dontExpectReply();
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_, value)
|
||||
.dontExpectReply();
|
||||
}
|
||||
|
||||
/*** ------------------- ***/
|
||||
/*** AsyncPropertySetter ***/
|
||||
/*** ------------------- ***/
|
||||
|
||||
inline AsyncPropertySetter::AsyncPropertySetter(IProxy& proxy, std::string_view propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(propertyName)
|
||||
inline AsyncPropertySetter::AsyncPropertySetter(IProxy& proxy, const std::string& propertyName)
|
||||
: proxy_(proxy)
|
||||
, propertyName_(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncPropertySetter& AsyncPropertySetter::onInterface(std::string_view interfaceName)
|
||||
inline AsyncPropertySetter& AsyncPropertySetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
interfaceName_ = &interfaceName;
|
||||
|
||||
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)
|
||||
@@ -638,70 +502,45 @@ 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>>
|
||||
, "Property set callback function must accept std::optional<Error> only" );
|
||||
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
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("Set")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_, std::move(value_))
|
||||
.uponReplyInvoke(std::forward<Function>(callback));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
[[nodiscard]] Slot AsyncPropertySetter::uponReplyInvoke(Function&& callback, return_slot_t)
|
||||
{
|
||||
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
|
||||
|
||||
return proxy_.callMethodAsync("Set")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_, std::move(value_))
|
||||
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_, std::move(value_))
|
||||
.uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
inline std::future<void> AsyncPropertySetter::getResultAsFuture()
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("Set")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_, propertyName_, std::move(value_))
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_, propertyName_, std::move(value_))
|
||||
.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 ***/
|
||||
/*** ------------------- ***/
|
||||
|
||||
inline AllPropertiesGetter::AllPropertiesGetter(IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
inline std::map<PropertyName, Variant> AllPropertiesGetter::onInterface(std::string_view interfaceName)
|
||||
inline std::map<std::string, Variant> AllPropertiesGetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
std::map<PropertyName, Variant> props;
|
||||
std::map<std::string, Variant> props;
|
||||
proxy_.callMethod("GetAll")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(std::move(interfaceName))
|
||||
.storeResultsTo(props);
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(interfaceName)
|
||||
.storeResultsTo(props);
|
||||
return props;
|
||||
}
|
||||
|
||||
@@ -714,59 +553,35 @@ namespace sdbus {
|
||||
{
|
||||
}
|
||||
|
||||
inline AsyncAllPropertiesGetter& AsyncAllPropertiesGetter::onInterface(std::string_view interfaceName)
|
||||
inline AsyncAllPropertiesGetter& AsyncAllPropertiesGetter::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
interfaceName_ = &interfaceName;
|
||||
|
||||
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>>
|
||||
, "All properties get callback function must accept std::optional<Error> and a map of property names to their values" );
|
||||
static_assert( std::is_invocable_r_v<void, _Function, std::optional<Error>, std::map<std::string, 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
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("GetAll")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_)
|
||||
.uponReplyInvoke(std::forward<Function>(callback));
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_)
|
||||
.uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
[[nodiscard]] Slot AsyncAllPropertiesGetter::uponReplyInvoke(Function&& callback, return_slot_t)
|
||||
inline std::future<std::map<std::string, Variant>> AsyncAllPropertiesGetter::getResultAsFuture()
|
||||
{
|
||||
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
|
||||
assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("GetAll")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_)
|
||||
.uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
}
|
||||
|
||||
inline std::future<std::map<PropertyName, Variant>> AsyncAllPropertiesGetter::getResultAsFuture()
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.callMethodAsync("GetAll")
|
||||
.onInterface(DBUS_PROPERTIES_INTERFACE_NAME)
|
||||
.withArguments(interfaceName_)
|
||||
.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>>();
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.withArguments(*interfaceName_)
|
||||
.getResultAsFuture<std::map<std::string, Variant>>();
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
+14
-30
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Error.h
|
||||
*
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef SDBUS_CXX_ERROR_H_
|
||||
#define SDBUS_CXX_ERROR_H_
|
||||
|
||||
#include <cerrno>
|
||||
#include <errno.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -43,34 +43,19 @@ namespace sdbus {
|
||||
: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
// Strong type representing the D-Bus error name
|
||||
class Name : public std::string
|
||||
{
|
||||
public:
|
||||
Name() = default;
|
||||
explicit Name(std::string value)
|
||||
: std::string(std::move(value))
|
||||
{}
|
||||
explicit Name(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
explicit Error(Name name, const char* message = nullptr)
|
||||
: Error(std::move(name), std::string(message ? message : ""))
|
||||
explicit Error(const std::string& name, const char* message = nullptr)
|
||||
: Error(name, std::string(message ? message : ""))
|
||||
{
|
||||
}
|
||||
|
||||
Error(Name name, std::string message)
|
||||
: std::runtime_error(!message.empty() ? "[" + name + "] " + message : "[" + name + "]")
|
||||
, name_(std::move(name))
|
||||
, message_(std::move(message))
|
||||
Error(const std::string& name, const std::string& message)
|
||||
: std::runtime_error("[" + name + "] " + message)
|
||||
, name_(name)
|
||||
, message_(message)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] const Name& getName() const
|
||||
[[nodiscard]] const std::string& getName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
@@ -86,20 +71,19 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
private:
|
||||
Name name_;
|
||||
std::string name_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
Error createError(int errNo, std::string customMsg = {});
|
||||
sdbus::Error createError(int errNo, const std::string& customMsg);
|
||||
|
||||
inline const Error::Name SDBUSCPP_ERROR_NAME{"org.sdbuscpp.Error"};
|
||||
} // namespace sdbus
|
||||
inline const char* SDBUSCPP_ERROR_NAME = "org.sdbuscpp.Error";
|
||||
}
|
||||
|
||||
// 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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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_ */
|
||||
|
||||
+75
-113
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IConnection.h
|
||||
*
|
||||
@@ -35,15 +35,11 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
// Forward declarations
|
||||
struct sd_bus;
|
||||
struct sd_event;
|
||||
namespace sdbus {
|
||||
class Message;
|
||||
class ObjectPath;
|
||||
class BusName;
|
||||
using ServiceName = BusName;
|
||||
} // namespace sdbus
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@@ -64,6 +60,31 @@ namespace sdbus {
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
|
||||
/*!
|
||||
* @brief Requests D-Bus name on the connection
|
||||
*
|
||||
* @param[in] name Name to request
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void requestName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Releases D-Bus name on the connection
|
||||
*
|
||||
* @param[in] name Name to release
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void releaseName(const std::string& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Retrieves the unique name of a connection. E.g. ":1.xx"
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getUniqueName() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Enters I/O event loop on this bus connection
|
||||
*
|
||||
@@ -92,7 +113,7 @@ namespace sdbus {
|
||||
virtual void leaveEventLoop() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Attaches the bus connection to a sd-event event loop
|
||||
* @brief Attaches the bus connection to an sd-event event loop
|
||||
*
|
||||
* @param[in] event sd-event event loop object
|
||||
* @param[in] priority Specified priority
|
||||
@@ -104,7 +125,7 @@ namespace sdbus {
|
||||
virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Detaches the bus connection from a sd-event event loop
|
||||
* @brief Detaches the bus connection from an sd-event event loop
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@@ -144,7 +165,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 a sd-event event loop, use
|
||||
* To attach the bus connection to an sd-event event loop, use
|
||||
* attachSdEventLoop() function.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
@@ -168,7 +189,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 a sd-event event loop through attachSdEventLoop().
|
||||
* connected to an sd-event event loop through attachSdEventLoop().
|
||||
* It is invoked automatically when necessary.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
@@ -207,8 +228,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
|
||||
@@ -223,7 +244,6 @@ namespace sdbus {
|
||||
|
||||
/*!
|
||||
* @brief Adds an ObjectManager at the specified D-Bus object path
|
||||
* @param[in] objectPath Object path at which the ObjectManager interface shall be installed
|
||||
*
|
||||
* Creates an ObjectManager interface at the specified object path on
|
||||
* the connection. This is a convenient way to interrogate a connection
|
||||
@@ -232,52 +252,12 @@ namespace sdbus {
|
||||
* This call creates a floating registration. The ObjectManager will
|
||||
* be there for the object path until the connection is destroyed.
|
||||
*
|
||||
* Another, recommended way to add object managers is directly through IObject API.
|
||||
* Another, recommended way to add object managers is directly through
|
||||
* IObject API.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addObjectManager(const ObjectPath& objectPath) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds an ObjectManager at the specified D-Bus object path
|
||||
* @param[in] objectPath Object path at which the ObjectManager interface shall be installed
|
||||
* @return Slot handle owning the registration
|
||||
*
|
||||
* Creates an ObjectManager interface at the specified object path on
|
||||
* the connection. This is a convenient way to interrogate a connection
|
||||
* to see what objects it has.
|
||||
*
|
||||
* This call returns an owning slot. The lifetime of the ObjectManager
|
||||
* interface is bound to the lifetime of the returned slot instance.
|
||||
*
|
||||
* Another, recommended way to add object managers is directly through IObject API.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addObjectManager(const ObjectPath& objectPath, return_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief 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
|
||||
*
|
||||
* The method installs a match rule for messages received on the specified bus connection.
|
||||
* The syntax of the match rule expression passed in match is described in the D-Bus specification.
|
||||
* The specified handler function callback is called for each incoming message matching the specified
|
||||
* expression. The match is installed synchronously when connected to a bus broker, i.e. the call
|
||||
* sends a control message requesting the match to be added to the broker and waits until the broker
|
||||
* confirms the match has been installed successfully.
|
||||
*
|
||||
* The method installs a floating match rule for messages received on the specified bus connection.
|
||||
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
|
||||
* is bound to the lifetime of the bus connection.
|
||||
*
|
||||
* For more information, consult `man sd_bus_add_match`.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addMatch(const std::string& match, message_handler callback) = 0;
|
||||
virtual void addObjectManager(const std::string& objectPath, floating_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Installs a match rule for messages received on this bus connection
|
||||
@@ -293,37 +273,31 @@ namespace sdbus {
|
||||
* sends a control message requesting the match to be added to the broker and waits until the broker
|
||||
* confirms the match has been installed successfully.
|
||||
*
|
||||
* The lifetime of the match rule is bound to the lifetime of the returned slot instance. Destroying
|
||||
* the slot instance implies uninstalling of the match rule from the bus connection.
|
||||
* Simply let go of the slot instance to uninstall the match rule from the bus connection. The slot
|
||||
* must not outlive the connection for the slot is associated with it.
|
||||
*
|
||||
* For more information, consult `man sd_bus_add_match`.
|
||||
*
|
||||
* @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) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Asynchronously installs a floating match rule for messages received on this bus connection
|
||||
* @brief 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
|
||||
*
|
||||
* 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.
|
||||
* The `installCallback' callable is called when the response is later received, with the response message
|
||||
* from the broker as parameter. If it's an empty function object, a default implementation is used that
|
||||
* terminates the bus connection should installing the match fail.
|
||||
*
|
||||
* The method installs a floating match rule for messages received on the specified bus connection.
|
||||
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
|
||||
* is bound to the lifetime of the bus connection.
|
||||
*
|
||||
* For more information, consult `man sd_bus_add_match_async`.
|
||||
* Refer to the @c addMatch(const std::string& match, message_handler callback) documentation for more
|
||||
* information.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0;
|
||||
virtual void addMatch(const std::string& match, message_handler callback, floating_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Asynchronously installs a match rule for messages received on this bus connection
|
||||
@@ -339,42 +313,30 @@ namespace sdbus {
|
||||
* from the broker as parameter. If it's an empty function object, a default implementation is used that
|
||||
* terminates the bus connection should installing the match fail.
|
||||
*
|
||||
* The lifetime of the match rule is bound to the lifetime of the returned slot instance. Destroying
|
||||
* the slot instance implies the uninstalling of the match rule from the bus connection.
|
||||
*
|
||||
* For more information, consult `man sd_bus_add_match_async`.
|
||||
* Refer to the @c addMatch(const std::string& match, message_handler callback) documentation, and consult
|
||||
* `man sd_bus_add_match`, for more information.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, return_slot_t ) = 0;
|
||||
[[nodiscard]] virtual Slot addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Retrieves the unique name of a connection. E.g. ":1.xx"
|
||||
* @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
|
||||
*
|
||||
* The method installs a floating match rule for messages received on the specified bus connection.
|
||||
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
|
||||
* is bound to the lifetime of the bus connection.
|
||||
*
|
||||
* Refer to the @c addMatch(const std::string& match, message_handler callback, message_handler installCallback)
|
||||
* documentation for more information.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual BusName getUniqueName() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Requests a well-known D-Bus service name on a bus
|
||||
*
|
||||
* @param[in] name Name to request
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void requestName(const ServiceName& name) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Releases an acquired well-known D-Bus service name on a bus
|
||||
*
|
||||
* @param[in] name Name to release
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void releaseName(const ServiceName& name) = 0;
|
||||
virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @struct PollData
|
||||
@@ -426,8 +388,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 +402,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection();
|
||||
[[nodiscard]] std::unique_ptr<sdbus::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 +412,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection(const ServiceName& name);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection(const std::string& name);
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system bus connection
|
||||
@@ -459,7 +421,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createSystemBusConnection();
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection();
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system bus connection with a name
|
||||
@@ -469,7 +431,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createSystemBusConnection(const ServiceName& name);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name);
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus session bus connection
|
||||
@@ -478,7 +440,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnection();
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection();
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus session bus connection with a name
|
||||
@@ -488,7 +450,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnection(const ServiceName& name);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name);
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus session bus connection at a custom address
|
||||
@@ -500,7 +462,7 @@ namespace sdbus {
|
||||
*
|
||||
* Consult manual pages for `sd_bus_set_address` of the underlying sd-bus library for more information.
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createSessionBusConnectionWithAddress(const std::string& address);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string& address);
|
||||
|
||||
/*!
|
||||
* @brief Creates/opens D-Bus system connection on a remote host using ssh
|
||||
@@ -510,7 +472,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createRemoteSystemBusConnection(const std::string& host);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host);
|
||||
|
||||
/*!
|
||||
* @brief Opens direct D-Bus connection at a custom address
|
||||
@@ -520,7 +482,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createDirectBusConnection(const std::string& address);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address);
|
||||
|
||||
/*!
|
||||
* @brief Opens direct D-Bus connection at the given file descriptor
|
||||
@@ -533,7 +495,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createDirectBusConnection(int fd);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd);
|
||||
|
||||
/*!
|
||||
* @brief Opens direct D-Bus connection at fd as a server
|
||||
@@ -549,7 +511,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createServerBus(int fd);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createServerBus(int fd);
|
||||
|
||||
/*!
|
||||
* @brief Creates sdbus-c++ bus connection representation out of underlying sd_bus instance
|
||||
@@ -578,7 +540,7 @@ namespace sdbus {
|
||||
* auto con = sdbus::createBusConnection(bus); // IConnection consumes sd_bus object
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createBusConnection(sd_bus *bus);
|
||||
} // namespace sdbus
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus);
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_ICONNECTION_H_ */
|
||||
|
||||
+139
-231
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IObject.h
|
||||
*
|
||||
@@ -41,8 +41,7 @@
|
||||
namespace sdbus {
|
||||
class Signal;
|
||||
class IConnection;
|
||||
class ObjectPath;
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@@ -61,67 +60,27 @@ namespace sdbus {
|
||||
***********************************************/
|
||||
class IObject
|
||||
{
|
||||
public: // High-level, convenience API
|
||||
public:
|
||||
virtual ~IObject() = default;
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] vtable Individual instances of VTable item structures stored in a vector
|
||||
* @return VTableAdder high-level helper class
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* Parameter `vtable' represents a vtable definition that may contain method declarations
|
||||
* (using MethodVTableItem struct), property declarations (using PropertyVTableItem
|
||||
* struct), signal declarations (using SignalVTableItem struct), or global interface
|
||||
* flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime.
|
||||
*
|
||||
* When called like `addVTable(vtable).forInterface(interface)`, then an internal registration
|
||||
* slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance.
|
||||
* When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal
|
||||
* registration slot is created for the vtable and is returned to the caller. Keeping the slot means
|
||||
* keep the registration "alive". Destroying the slot means that the vtable is not needed anymore,
|
||||
* and the vtable gets removed from the object. This allows for "dynamic" object API where vtables
|
||||
* can be added or removed by the user at runtime.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] VTableAdder addVTable(std::vector<VTableItem> vtable);
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] items Individual instances of VTable item structures
|
||||
* @return VTableAdder high-level helper class
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* Parameter pack contains vtable definition that may contain method declarations
|
||||
* Parameter `items' represents a vtable definition that may contain method declarations
|
||||
* (using MethodVTableItem struct), property declarations (using PropertyVTableItem
|
||||
* struct), signal declarations (using SignalVTableItem struct), or global interface
|
||||
* flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
|
||||
* Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime.
|
||||
*
|
||||
* When called like `addVTable(items...).forInterface(interface)`, then an internal registration
|
||||
* slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance.
|
||||
* When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal
|
||||
* registration slot is created for the vtable and is returned to the caller. Keeping the slot means
|
||||
* keep the registration "alive". Destroying the slot means that the vtable is not needed anymore,
|
||||
* and the vtable gets removed from the object. This allows for "dynamic" object API where vtables
|
||||
* can be added or removed by the user at runtime.
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* match slot is created and its lifetime is tied to the lifetime of the Object instance.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
@@ -129,9 +88,119 @@ 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>> && ...)> > // NOLINT(modernize-use-constraints): We are C++17 compatible at the moment
|
||||
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
|
||||
void addVTable(std::string interfaceName, VTableItems&&... items);
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] vtable A list of individual descriptions in the form of VTable item instances
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
|
||||
* property declarations (using PropertyVTableItem struct), signal declarations (using
|
||||
* SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* match slot is created and its lifetime is tied to the lifetime of the Object instance.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addVTable(std::string interfaceName, std::vector<VTableItem> vtable) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] vtable A list of individual descriptions in the form of VTable item instances
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
|
||||
* property declarations (using PropertyVTableItem struct), signal declarations (using
|
||||
* SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* match slot is created and is returned to the caller. The returned slot should be destroyed
|
||||
* when the vtable is not needed anymore. This allows for "dynamic" object API where vtables
|
||||
* can be added or removed by the user at runtime.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addVTable(std::string interfaceName, std::vector<VTableItem> vtable, return_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief A little more convenient overload of addVTable() above
|
||||
*
|
||||
* This version allows method chaining for a little safer and more readable VTable registration.
|
||||
*
|
||||
* See addVTable() overloads above for detailed documentation.
|
||||
*/
|
||||
template < typename... VTableItems
|
||||
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
|
||||
[[nodiscard]] VTableAdder addVTable(VTableItems&&... items);
|
||||
|
||||
/*!
|
||||
* @brief A little more convenient overload of addVTable() above
|
||||
*
|
||||
* This version allows method chaining for a little safer and more readable VTable registration.
|
||||
*
|
||||
* See addVTable() overloads above for detailed documentation.
|
||||
*/
|
||||
[[nodiscard]] VTableAdder addVTable(std::vector<VTableItem> vtable);
|
||||
|
||||
/*!
|
||||
* @brief Unregisters object's API and removes object from the bus
|
||||
*
|
||||
* This method unregisters the object, its interfaces, methods, signals and properties
|
||||
* from the bus. Unregistration is done automatically also in object's destructor. This
|
||||
* method makes sense if, in the process of object removal, we need to make sure that
|
||||
* callbacks are unregistered explicitly before the final destruction of the object instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregister() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Creates a signal message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A signal message
|
||||
*
|
||||
* Serialize signal arguments into the returned message and emit the signal by passing
|
||||
* the message with serialized arguments to the @c emitSignal function.
|
||||
* Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Signal createSignal(const std::string& interfaceName, const std::string& signalName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits signal for this object path
|
||||
*
|
||||
* @param[in] message Signal message to be sent out
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitSignal(const sdbus::Signal& message) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits signal on D-Bus
|
||||
*
|
||||
@@ -146,24 +215,13 @@ namespace sdbus {
|
||||
* @code
|
||||
* int arg1 = ...;
|
||||
* double arg2 = ...;
|
||||
* SignalName fooSignal{"fooSignal"};
|
||||
* object_.emitSignal(fooSignal).onInterface("com.kistler.foo").withArguments(arg1, arg2);
|
||||
* object_.emitSignal("fooSignal").onInterface("com.kistler.foo").withArguments(arg1, arg2);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalEmitter emitSignal(const SignalName& signalName);
|
||||
|
||||
/*!
|
||||
* @copydoc IObject::emitSignal(const SignalName&)
|
||||
*/
|
||||
[[nodiscard]] SignalEmitter emitSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @copydoc IObject::emitSignal(const SignalName&)
|
||||
*/
|
||||
[[nodiscard]] SignalEmitter emitSignal(const char* signalName);
|
||||
|
||||
/*!
|
||||
* @brief Emits PropertyChanged signal for specified properties under a given interface of this object path
|
||||
*
|
||||
@@ -172,12 +230,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector<PropertyName>& propNames) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&,const std::vector<PropertyName>&)
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const char* interfaceName, const std::vector<PropertyName>& propNames) = 0;
|
||||
virtual void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits PropertyChanged signal for all properties on a given interface of this object path
|
||||
@@ -186,12 +239,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&)
|
||||
*/
|
||||
virtual void emitPropertiesChangedSignal(const char* interfaceName) = 0;
|
||||
virtual void emitPropertiesChangedSignal(const std::string& interfaceName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesAdded signal on this object path
|
||||
@@ -216,7 +264,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces) = 0;
|
||||
virtual void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits InterfacesRemoved signal on this object path
|
||||
@@ -238,7 +286,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitInterfacesRemovedSignal(const std::vector<InterfaceName>& interfaces) = 0;
|
||||
virtual void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds an ObjectManager interface at the path of this D-Bus object
|
||||
@@ -247,28 +295,22 @@ namespace sdbus {
|
||||
* the connection. This is a convenient way to interrogate a connection
|
||||
* to see what objects it has.
|
||||
*
|
||||
* This call creates a so-called floating registration. This means that
|
||||
* the ObjectManager interface stays there for the lifetime of the object.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addObjectManager() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds an ObjectManager interface at the path of this D-Bus object
|
||||
*
|
||||
* @return Slot handle owning the registration
|
||||
*
|
||||
* Creates an ObjectManager interface at the specified object path on
|
||||
* the connection. This is a convenient way to interrogate a connection
|
||||
* to see what objects it has.
|
||||
*
|
||||
* The lifetime of the ObjectManager interface is bound to the lifetime
|
||||
* of the returned slot instance.
|
||||
* @brief Removes an ObjectManager interface from the path of this D-Bus object
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addObjectManager(return_slot_t) = 0;
|
||||
virtual void removeObjectManager() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Tests whether ObjectManager interface is added at the path of this D-Bus object
|
||||
* @return True if ObjectManager interface is there, false otherwise
|
||||
*/
|
||||
[[nodiscard]] virtual bool hasObjectManager() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Provides D-Bus connection used by the object
|
||||
@@ -280,7 +322,7 @@ namespace sdbus {
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
*/
|
||||
[[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0;
|
||||
[[nodiscard]] virtual const std::string& getObjectPath() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Provides access to the currently processed D-Bus message
|
||||
@@ -296,151 +338,17 @@ namespace sdbus {
|
||||
* @return Currently processed D-Bus message
|
||||
*/
|
||||
[[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters object's API and removes object from the bus
|
||||
*
|
||||
* This method unregisters the object, its interfaces, methods, signals and properties
|
||||
* from the bus. Unregistration is done automatically also in object's destructor. This
|
||||
* method makes sense if, in the process of object removal, we need to make sure that
|
||||
* callbacks are unregistered explicitly before the final destruction of the object instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregister() = 0;
|
||||
|
||||
// Lower-level, message-based API
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] items Individual instances of VTable item structures
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* Parameter `items' represents a vtable definition that may contain method declarations
|
||||
* (using MethodVTableItem struct), property declarations (using PropertyVTableItem
|
||||
* struct), signal declarations (using SignalVTableItem struct), or global interface
|
||||
* flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* registration slot is created and its lifetime is tied to the lifetime of the Object instance.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @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>> && ...)> >
|
||||
void addVTable(InterfaceName interfaceName, VTableItems&&... items);
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] vtable A list of individual descriptions in the form of VTable item instances
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
|
||||
* property declarations (using PropertyVTableItem struct), signal declarations (using
|
||||
* SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* registration slot is created and its lifetime is tied to the lifetime of the Object instance.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface the the vtable is registered for
|
||||
* @param[in] vtable A list of individual descriptions in the form of VTable item instances
|
||||
*
|
||||
* This method is used to declare attributes for the object under the given interface.
|
||||
* The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
|
||||
* property declarations (using PropertyVTableItem struct), signal declarations (using
|
||||
* SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
|
||||
*
|
||||
* An interface can have any number of vtables attached to it.
|
||||
*
|
||||
* Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
|
||||
*
|
||||
* The method can be called at any time during object's lifetime. For each vtable an internal
|
||||
* registration slot is created and is returned to the caller. The returned slot should be destroyed
|
||||
* when the vtable is not needed anymore. This allows for "dynamic" object API where vtables
|
||||
* can be added or removed by the user at runtime.
|
||||
*
|
||||
* The function provides strong exception guarantee. The state of the object remains
|
||||
* unmodified in face of an exception.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable, return_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Creates a signal message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A signal message
|
||||
*
|
||||
* Serialize signal arguments into the returned message and emit the signal by passing
|
||||
* the message with serialized arguments to the @c emitSignal function.
|
||||
* Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Emits signal for this object path
|
||||
*
|
||||
* @param[in] message Signal message to be sent out
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void emitSignal(const Signal& message) = 0;
|
||||
|
||||
protected: // Internal API for efficiency reasons used by high-level API helper classes
|
||||
friend SignalEmitter;
|
||||
|
||||
[[nodiscard]] virtual Signal createSignal(const char* interfaceName, const char* signalName) const = 0;
|
||||
};
|
||||
|
||||
// Out-of-line member definitions
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const SignalName& signalName)
|
||||
{
|
||||
return {*this, signalName};
|
||||
}
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
|
||||
{
|
||||
return {*this, signalName.c_str()};
|
||||
}
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const char* signalName)
|
||||
{
|
||||
return {*this, signalName};
|
||||
return SignalEmitter(*this, signalName);
|
||||
}
|
||||
|
||||
template <typename... VTableItems, typename>
|
||||
void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items)
|
||||
void IObject::addVTable(std::string interfaceName, VTableItems&&... items)
|
||||
{
|
||||
addVTable(std::move(interfaceName), {std::forward<VTableItems>(items)...});
|
||||
}
|
||||
@@ -453,7 +361,7 @@ namespace sdbus {
|
||||
|
||||
inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)
|
||||
{
|
||||
return {*this, std::move(vtable)};
|
||||
return VTableAdder(*this, std::move(vtable));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -474,11 +382,11 @@ namespace sdbus {
|
||||
* auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IObject> createObject(IConnection& connection, ObjectPath objectPath);
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, std::string objectPath);
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl> // NOLINT(misc-header-include-cycle)
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl>
|
||||
#include <sdbus-c++/VTableItems.inl>
|
||||
|
||||
#endif /* SDBUS_CXX_IOBJECT_H_ */
|
||||
|
||||
+222
-556
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IProxy.h
|
||||
*
|
||||
@@ -29,26 +29,23 @@
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Awaitable.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class MethodCall;
|
||||
class MethodReply;
|
||||
class IConnection;
|
||||
class ObjectPath;
|
||||
class PendingAsyncCall;
|
||||
namespace internal {
|
||||
class Proxy;
|
||||
} // namespace internal
|
||||
} // namespace sdbus
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@@ -68,9 +65,138 @@ namespace sdbus {
|
||||
***********************************************/
|
||||
class IProxy
|
||||
{
|
||||
public: // High-level, convenience API
|
||||
public:
|
||||
virtual ~IProxy() = default;
|
||||
|
||||
/*!
|
||||
* @brief Creates a method call message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that provides a given method
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A method call message
|
||||
*
|
||||
* Serialize method arguments into the returned message and invoke the method by passing
|
||||
* the message with serialized arguments to the @c callMethod function.
|
||||
* Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return A method reply message
|
||||
*
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. So-called light-weight proxies (ones created with `dont_run_event_loop_thread`
|
||||
* tag are designed for exactly that purpose.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure (also in case the remote function returned an error)
|
||||
*/
|
||||
virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout = 0) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t)
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return Cookie for the the pending asynchronous call
|
||||
*
|
||||
* This is a callback-based way of asynchronously calling a remote D-Bus method.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, uint64_t timeout = 0 ) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, const std::chrono::duration<_Rep, _Period>& timeout );
|
||||
|
||||
/*!
|
||||
* @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.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided future object will be set to contain the reply (or sdbus::Error
|
||||
* in case the remote method threw an exception).
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::future<MethodReply> callMethodAsync(const MethodCall& message, with_future_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously, with custom timeout
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided future object will be set to contain the reply (or sdbus::Error
|
||||
* in case the remote method threw an exception, or the call timed out).
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::future<MethodReply> callMethodAsync( const MethodCall& message
|
||||
, uint64_t timeout
|
||||
, with_future_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
std::future<MethodReply> callMethodAsync( const MethodCall& message
|
||||
, const std::chrono::duration<_Rep, _Period>& timeout
|
||||
, with_future_t );
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object
|
||||
*
|
||||
@@ -85,24 +211,13 @@ namespace sdbus {
|
||||
* Example of use:
|
||||
* @code
|
||||
* int result, a = ..., b = ...;
|
||||
* MethodName multiply{"multiply"};
|
||||
* object_.callMethod(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
* object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] MethodInvoker callMethod(const MethodName& methodName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodName&)
|
||||
*/
|
||||
[[nodiscard]] MethodInvoker callMethod(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodName&)
|
||||
*/
|
||||
[[nodiscard]] MethodInvoker callMethod(const char* methodName);
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously
|
||||
*
|
||||
@@ -117,8 +232,7 @@ namespace sdbus {
|
||||
* Example of use:
|
||||
* @code
|
||||
* int a = ..., b = ...;
|
||||
* MethodName multiply{"multiply"};
|
||||
* object_.callMethodAsync(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result)
|
||||
* object_.callMethodAsync("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result)
|
||||
* {
|
||||
* std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl;
|
||||
* });
|
||||
@@ -126,17 +240,43 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] AsyncMethodInvoker callMethodAsync(const MethodName& methodName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethodAsync(const MethodName&)
|
||||
*/
|
||||
[[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethodAsync(const MethodName&)
|
||||
* @brief Registers a handler for the desired signal emitted by the D-Bus object
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] AsyncMethodInvoker callMethodAsync(const char* methodName);
|
||||
virtual void registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers a handler for the desired signal emitted by the D-Bus object
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* @return RAII-style slot handle representing the ownership of the subscription
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call. The subscription
|
||||
* is unregistered when the client destroys the returned slot object.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal handler for a given signal of the D-Bus object
|
||||
@@ -154,25 +294,23 @@ namespace sdbus {
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.uponSignal("stateChanged").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onStateChanged(arg1, arg2); });
|
||||
* sdbus::InterfaceName foo{"com.kistler.foo"};
|
||||
* sdbus::SignalName levelChanged{"levelChanged"};
|
||||
* object_.uponSignal(levelChanged).onInterface(foo).call([this](uint16_t level){ this->onLevelChanged(level); });
|
||||
* object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalSubscriber uponSignal(const SignalName& signalName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::uponSignal(const SignalName&)
|
||||
*/
|
||||
[[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::uponSignal(const SignalName&)
|
||||
* @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls
|
||||
*
|
||||
* Unregistration is done automatically also in proxy's destructor. This method makes
|
||||
* sense if, in the process of proxy removal, we need to make sure that callbacks
|
||||
* are unregistered explicitly before the final destruction of the proxy instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalSubscriber uponSignal(const char* signalName);
|
||||
virtual void unregister() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Gets value of a property of the D-Bus object
|
||||
@@ -187,19 +325,11 @@ namespace sdbus {
|
||||
* Example of use:
|
||||
* @code
|
||||
* int state = object.getProperty("state").onInterface("com.kistler.foo");
|
||||
* sdbus::InterfaceName foo{"com.kistler.foo"};
|
||||
* sdbus::PropertyName level{"level"};
|
||||
* int level = object.getProperty(level).onInterface(foo);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertyGetter getProperty(const PropertyName& propertyName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::getProperty(const PropertyName&)
|
||||
*/
|
||||
[[nodiscard]] PropertyGetter getProperty(std::string_view propertyName);
|
||||
[[nodiscard]] PropertyGetter getProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Gets value of a property of the D-Bus object asynchronously
|
||||
@@ -219,12 +349,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] AsyncPropertyGetter getPropertyAsync(const PropertyName& propertyName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::getPropertyAsync(const PropertyName&)
|
||||
*/
|
||||
[[nodiscard]] AsyncPropertyGetter getPropertyAsync(std::string_view propertyName);
|
||||
[[nodiscard]] AsyncPropertyGetter getPropertyAsync(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets value of a property of the D-Bus object
|
||||
@@ -246,12 +371,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertySetter setProperty(const PropertyName& propertyName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::setProperty(const PropertyName&)
|
||||
*/
|
||||
[[nodiscard]] PropertySetter setProperty(std::string_view propertyName);
|
||||
[[nodiscard]] PropertySetter setProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets value of a property of the D-Bus object asynchronously
|
||||
@@ -271,12 +391,7 @@ namespace sdbus {
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] AsyncPropertySetter setPropertyAsync(const PropertyName& propertyName);
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::setPropertyAsync(const PropertyName&)
|
||||
*/
|
||||
[[nodiscard]] AsyncPropertySetter setPropertyAsync(std::string_view propertyName);
|
||||
[[nodiscard]] AsyncPropertySetter setPropertyAsync(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Gets values of all properties of the D-Bus object
|
||||
@@ -305,7 +420,7 @@ namespace sdbus {
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* auto callback = [](std::optional<sdbus::Error> err, const std::map<PropertyName, Variant>>& properties){ ... };
|
||||
* auto callback = [](std::optional<sdbus::Error> err, const std::map<std::string, Variant>>& properties){ ... };
|
||||
* auto props = object.getAllPropertiesAsync().onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback));
|
||||
* @endcode
|
||||
*
|
||||
@@ -323,7 +438,7 @@ namespace sdbus {
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
*/
|
||||
[[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0;
|
||||
[[nodiscard]] virtual const std::string& getObjectPath() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Provides access to the currently processed D-Bus message
|
||||
@@ -339,372 +454,6 @@ namespace sdbus {
|
||||
* @return Currently processed D-Bus message
|
||||
*/
|
||||
[[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls
|
||||
*
|
||||
* Unregistration is done automatically also in proxy's destructor. This method makes
|
||||
* sense if, in the process of proxy removal, we need to make sure that callbacks
|
||||
* are unregistered explicitly before the final destruction of the proxy instance.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregister() = 0;
|
||||
|
||||
// Lower-level, message-based API
|
||||
/*!
|
||||
* @brief Creates a method call message
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that provides a given method
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A method call message
|
||||
*
|
||||
* Serialize method arguments into the returned message and invoke the method by passing
|
||||
* the message with serialized arguments to the @c callMethod function.
|
||||
* Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual MethodCall createMethodCall(const InterfaceName& interfaceName, const MethodName& methodName) const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @return A method reply message
|
||||
*
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. So-called light-weight proxies (ones running without an event loop thread)
|
||||
* tag are designed for exactly that purpose.
|
||||
*
|
||||
* The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure (also in case the remote function returned an error)
|
||||
*/
|
||||
virtual MethodReply callMethod(const MethodCall& message) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the remote D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @param[in] timeout Method call timeout (in microseconds)
|
||||
* @return A method reply message
|
||||
*
|
||||
* The call does not block if the method call has dont-expect-reply flag set. In that case,
|
||||
* the call returns immediately and the return value is an empty, invalid method reply.
|
||||
*
|
||||
* The call blocks otherwise, waiting for the remote peer to send back a reply or an error,
|
||||
* or until the call times out.
|
||||
*
|
||||
* While blocking, other concurrent operations (in other threads) on the underlying bus
|
||||
* connection are stalled until the call returns. This is not an issue in vast majority of
|
||||
* (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving
|
||||
* shared bus connections, this may be an issue. It is advised to instead use an asynchronous
|
||||
* callMethod() function overload, which does not block the bus connection, or do the synchronous
|
||||
* call from another Proxy instance created just before the call and then destroyed (which is
|
||||
* anyway quite a typical approach in D-Bus implementations). Such proxy instance must have
|
||||
* its own bus connection. So-called light-weight proxies (ones running without an event loop thread)
|
||||
* tag are designed for exactly that purpose.
|
||||
*
|
||||
* If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure (also in case the remote function returned an error)
|
||||
*/
|
||||
virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t)
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @return Observing handle for the the pending asynchronous call
|
||||
*
|
||||
* This is a callback-based way of asynchronously calling a remote D-Bus method.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* An non-owning, observing async call handle is returned that can be used to query call status or cancel the call.
|
||||
*
|
||||
* The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @return RAII-style slot handle representing the ownership of the async call
|
||||
*
|
||||
* This is a callback-based way of asynchronously calling a remote D-Bus method.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* A slot (an owning handle) is returned for the async call. Lifetime of the call is bound to the lifetime of the slot.
|
||||
* The slot can be used to cancel the method call at a later time by simply destroying it.
|
||||
*
|
||||
* The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously, with custom timeout
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @param[in] timeout Method call timeout (in microseconds)
|
||||
* @return Observing handle for the the pending asynchronous call
|
||||
*
|
||||
* This is a callback-based way of asynchronously calling a remote D-Bus method.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* An non-owning, observing async call handle is returned that can be used to query call status or cancel the call.
|
||||
*
|
||||
* If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, uint64_t timeout ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously, with custom timeout
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @param[in] timeout Method call timeout (in microseconds)
|
||||
* @return RAII-style slot handle representing the ownership of the async call
|
||||
*
|
||||
* This is a callback-based way of asynchronously calling a remote D-Bus method.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the bus
|
||||
* connection I/O event loop thread.
|
||||
*
|
||||
* A slot (an owning handle) is returned for the async call. Lifetime of the call is bound to the lifetime of the slot.
|
||||
* The slot can be used to cancel the method call at a later time by simply destroying it.
|
||||
*
|
||||
* If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use API on a higher level of abstraction defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
|
||||
, 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>
|
||||
PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, 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>
|
||||
[[nodiscard]] Slot callMethodAsync( const MethodCall& message
|
||||
, 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
|
||||
* @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.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided future object will be set to contain the reply (or sdbus::Error
|
||||
* in case the remote method threw an exception).
|
||||
*
|
||||
* The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::future<MethodReply> callMethodAsync(const MethodCall& message, with_future_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the D-Bus object asynchronously, with custom timeout
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] timeout Method call timeout
|
||||
* @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.
|
||||
*
|
||||
* The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided future object will be set to contain the reply (or sdbus::Error
|
||||
* in case the remote method threw an exception, or the call timed out).
|
||||
*
|
||||
* If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout().
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::future<MethodReply> callMethodAsync( const MethodCall& message
|
||||
, uint64_t timeout
|
||||
, with_future_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t)
|
||||
*/
|
||||
template <typename Rep, typename Period>
|
||||
std::future<MethodReply> callMethodAsync( const MethodCall& message
|
||||
, 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
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* A signal can be subscribed to at any time during proxy lifetime. The subscription
|
||||
* is active immediately after the call, and stays active for the entire lifetime
|
||||
* of the Proxy object.
|
||||
*
|
||||
* To be able to unsubscribe from the signal at a later time, use the registerSignalHandler()
|
||||
* overload with request_slot tag.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers a handler for the desired signal emitted by the D-Bus object
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* @return RAII-style slot handle representing the ownership of the subscription
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call. The lifetime
|
||||
* of the subscription is bound to the lifetime of the slot object. The subscription
|
||||
* is unregistered by letting go of the slot object.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
protected: // Internal API for efficiency reasons used by high-level API helper classes
|
||||
friend MethodInvoker;
|
||||
friend AsyncMethodInvoker;
|
||||
friend SignalSubscriber;
|
||||
|
||||
[[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;
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t ) = 0;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
@@ -743,139 +492,72 @@ namespace sdbus {
|
||||
|
||||
private:
|
||||
friend internal::Proxy;
|
||||
explicit PendingAsyncCall(std::weak_ptr<void> callInfo);
|
||||
PendingAsyncCall(std::weak_ptr<void> callData);
|
||||
|
||||
std::weak_ptr<void> callInfo_;
|
||||
private:
|
||||
std::weak_ptr<void> callData_;
|
||||
};
|
||||
|
||||
// Out-of-line member definitions
|
||||
|
||||
template <typename Rep, typename Period>
|
||||
inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<Rep, Period>& timeout)
|
||||
template <typename _Rep, typename _Period>
|
||||
inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout)
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return callMethod(message, microsecs.count());
|
||||
}
|
||||
|
||||
template <typename Rep, typename Period>
|
||||
template <typename _Rep, typename _Period>
|
||||
inline PendingAsyncCall IProxy::callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, const std::chrono::duration<Rep, Period>& timeout )
|
||||
, const std::chrono::duration<_Rep, _Period>& timeout )
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return callMethodAsync(message, std::move(asyncReplyCallback), microsecs.count());
|
||||
}
|
||||
|
||||
template <typename Rep, typename Period>
|
||||
inline Slot IProxy::callMethodAsync( const MethodCall& message
|
||||
, 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 {*this, methodName};
|
||||
}
|
||||
|
||||
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
|
||||
{
|
||||
return {*this, methodName.c_str()};
|
||||
}
|
||||
|
||||
inline MethodInvoker IProxy::callMethod(const char* methodName)
|
||||
{
|
||||
return {*this, methodName};
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker IProxy::callMethodAsync(const MethodName& methodName)
|
||||
{
|
||||
return {*this, methodName};
|
||||
return MethodInvoker(*this, methodName);
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker IProxy::callMethodAsync(const std::string& methodName)
|
||||
{
|
||||
return {*this, methodName.c_str()};
|
||||
}
|
||||
|
||||
inline AsyncMethodInvoker IProxy::callMethodAsync(const char* methodName)
|
||||
{
|
||||
return {*this, methodName};
|
||||
}
|
||||
|
||||
inline SignalSubscriber IProxy::uponSignal(const SignalName& signalName)
|
||||
{
|
||||
return {*this, signalName};
|
||||
return AsyncMethodInvoker(*this, methodName);
|
||||
}
|
||||
|
||||
inline SignalSubscriber IProxy::uponSignal(const std::string& signalName)
|
||||
{
|
||||
return {*this, signalName.c_str()};
|
||||
return SignalSubscriber(*this, signalName);
|
||||
}
|
||||
|
||||
inline SignalSubscriber IProxy::uponSignal(const char* signalName)
|
||||
inline PropertyGetter IProxy::getProperty(const std::string& propertyName)
|
||||
{
|
||||
return {*this, signalName};
|
||||
return PropertyGetter(*this, propertyName);
|
||||
}
|
||||
|
||||
inline PropertyGetter IProxy::getProperty(const PropertyName& propertyName)
|
||||
inline AsyncPropertyGetter IProxy::getPropertyAsync(const std::string& propertyName)
|
||||
{
|
||||
return {*this, propertyName};
|
||||
return AsyncPropertyGetter(*this, propertyName);
|
||||
}
|
||||
|
||||
inline PropertyGetter IProxy::getProperty(std::string_view propertyName)
|
||||
inline PropertySetter IProxy::setProperty(const std::string& propertyName)
|
||||
{
|
||||
return {*this, std::move(propertyName)};
|
||||
return PropertySetter(*this, propertyName);
|
||||
}
|
||||
|
||||
inline AsyncPropertyGetter IProxy::getPropertyAsync(const PropertyName& propertyName)
|
||||
inline AsyncPropertySetter IProxy::setPropertyAsync(const std::string& propertyName)
|
||||
{
|
||||
return {*this, propertyName};
|
||||
}
|
||||
|
||||
inline AsyncPropertyGetter IProxy::getPropertyAsync(std::string_view propertyName)
|
||||
{
|
||||
return {*this, std::move(propertyName)};
|
||||
}
|
||||
|
||||
inline PropertySetter IProxy::setProperty(const PropertyName& propertyName)
|
||||
{
|
||||
return {*this, propertyName};
|
||||
}
|
||||
|
||||
inline PropertySetter IProxy::setProperty(std::string_view propertyName)
|
||||
{
|
||||
return {*this, std::move(propertyName)};
|
||||
}
|
||||
|
||||
inline AsyncPropertySetter IProxy::setPropertyAsync(const PropertyName& propertyName)
|
||||
{
|
||||
return {*this, propertyName};
|
||||
}
|
||||
|
||||
inline AsyncPropertySetter IProxy::setPropertyAsync(std::string_view propertyName)
|
||||
{
|
||||
return {*this, std::move(propertyName)};
|
||||
return AsyncPropertySetter(*this, propertyName);
|
||||
}
|
||||
|
||||
inline AllPropertiesGetter IProxy::getAllProperties()
|
||||
@@ -910,9 +592,9 @@ namespace sdbus {
|
||||
* auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IProxy> createProxy( IConnection& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( sdbus::IConnection& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
@@ -936,12 +618,12 @@ namespace sdbus {
|
||||
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
|
||||
/*!
|
||||
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the proxy object
|
||||
* @param[in] destination Bus name that provides the remote D-Bus object
|
||||
@@ -963,19 +645,10 @@ 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<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<IProxy> createLightWeightProxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
@@ -994,11 +667,11 @@ namespace sdbus {
|
||||
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo");
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IProxy> createProxy( ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath );
|
||||
|
||||
/*!
|
||||
* @brief Creates a light-weight proxy object for a specific remote D-Bus object
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
* @param[in] destination Bus name that provides the remote D-Bus object
|
||||
* @param[in] objectPath Path of the remote D-Bus object
|
||||
@@ -1015,19 +688,12 @@ namespace sdbus {
|
||||
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread );
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<IProxy> createProxy( ServiceName destination
|
||||
, ObjectPath objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string 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<IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath);
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl> // NOLINT(misc-header-include-cycle)
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl>
|
||||
|
||||
#endif /* SDBUS_CXX_IPROXY_H_ */
|
||||
|
||||
+202
-365
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message.h
|
||||
*
|
||||
@@ -34,19 +34,15 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#ifdef __has_include
|
||||
# if __has_include(<span>)
|
||||
# include <span>
|
||||
# endif
|
||||
#if __cplusplus >= 202002L
|
||||
#include <span>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
@@ -54,13 +50,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
|
||||
class ISdBus;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@@ -97,34 +93,27 @@ namespace sdbus {
|
||||
Message& operator<<(double item);
|
||||
Message& operator<<(const char *item);
|
||||
Message& operator<<(const std::string &item);
|
||||
Message& operator<<(std::string_view item);
|
||||
Message& operator<<(const Variant &item);
|
||||
template <typename ...Elements>
|
||||
Message& operator<<(const std::variant<Elements...>& value);
|
||||
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);
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename Element, std::size_t Extent>
|
||||
Message& operator<<(const std::span<Element, Extent>& 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);
|
||||
#if __cplusplus >= 202002L
|
||||
template <typename _Element, std::size_t _Extent>
|
||||
Message& operator<<(const std::span<_Element, _Extent>& items);
|
||||
#endif
|
||||
// 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);
|
||||
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);
|
||||
@@ -138,88 +127,56 @@ namespace sdbus {
|
||||
Message& operator>>(char*& item);
|
||||
Message& operator>>(std::string &item);
|
||||
Message& operator>>(Variant &item);
|
||||
template <typename ...Elements>
|
||||
Message& operator>>(std::variant<Elements...>& value);
|
||||
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);
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename Element, std::size_t Extent>
|
||||
Message& operator>>(std::span<Element, Extent>& 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);
|
||||
#if __cplusplus >= 202002L
|
||||
template <typename _Element, std::size_t _Extent>
|
||||
Message& operator>>(std::span<_Element, _Extent>& items);
|
||||
#endif
|
||||
// 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 _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>
|
||||
Message& openContainer();
|
||||
Message& openContainer(const char* signature);
|
||||
Message& openContainer(const std::string& signature);
|
||||
Message& closeContainer();
|
||||
template <typename KeyType, typename ValueType>
|
||||
Message& openDictEntry();
|
||||
Message& openDictEntry(const char* signature);
|
||||
Message& openDictEntry(const std::string& signature);
|
||||
Message& closeDictEntry();
|
||||
template <typename ValueType>
|
||||
Message& openVariant();
|
||||
Message& openVariant(const char* signature);
|
||||
Message& openVariant(const std::string& signature);
|
||||
Message& closeVariant();
|
||||
template <typename... ValueTypes>
|
||||
Message& openStruct();
|
||||
Message& openStruct(const char* signature);
|
||||
Message& openStruct(const std::string& signature);
|
||||
Message& closeStruct();
|
||||
|
||||
template <typename ElementType>
|
||||
Message& enterContainer();
|
||||
Message& enterContainer(const char* signature);
|
||||
Message& enterContainer(const std::string& signature);
|
||||
Message& exitContainer();
|
||||
template <typename KeyType, typename ValueType>
|
||||
Message& enterDictEntry();
|
||||
Message& enterDictEntry(const char* signature);
|
||||
Message& enterDictEntry(const std::string& signature);
|
||||
Message& exitDictEntry();
|
||||
template <typename ValueType>
|
||||
Message& enterVariant();
|
||||
Message& enterVariant(const char* signature);
|
||||
Message& enterVariant(const std::string& signature);
|
||||
Message& exitVariant();
|
||||
template <typename... ValueTypes>
|
||||
Message& enterStruct();
|
||||
Message& enterStruct(const char* signature);
|
||||
Message& enterStruct(const std::string& signature);
|
||||
Message& exitStruct();
|
||||
|
||||
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);
|
||||
|
||||
explicit operator bool() const;
|
||||
void clearFlags();
|
||||
|
||||
const char* getInterfaceName() const;
|
||||
const char* getMemberName() const;
|
||||
const char* getSender() const;
|
||||
const char* getPath() const;
|
||||
const char* getDestination() const;
|
||||
uint64_t getCookie() const;
|
||||
// TODO: short docs in whole Message API
|
||||
std::pair<char, const char*> peekType() const;
|
||||
std::string getInterfaceName() const;
|
||||
std::string getMemberName() const;
|
||||
std::string getSender() const;
|
||||
std::string getPath() const;
|
||||
std::string getDestination() const;
|
||||
void peekType(std::string& type, std::string& contents) const;
|
||||
bool isValid() const;
|
||||
bool isEmpty() const;
|
||||
bool isAtEnd(bool complete) const;
|
||||
@@ -228,15 +185,6 @@ 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;
|
||||
@@ -248,29 +196,35 @@ 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);
|
||||
|
||||
template <typename _Dictionary>
|
||||
void serializeDictionary(const _Dictionary& items);
|
||||
template <typename _Dictionary>
|
||||
void deserializeDictionary(_Dictionary& items);
|
||||
|
||||
protected:
|
||||
Message() = default;
|
||||
explicit Message(internal::IConnection* connection) noexcept;
|
||||
Message(void *msg, internal::IConnection* connection) noexcept;
|
||||
Message(void *msg, internal::IConnection* connection, adopt_message_t) noexcept;
|
||||
explicit Message(internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus) noexcept;
|
||||
Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
friend Factory;
|
||||
|
||||
protected:
|
||||
void* msg_{};
|
||||
internal::IConnection* connection_{};
|
||||
internal::ISdBus* sdbus_{};
|
||||
mutable bool ok_{true};
|
||||
};
|
||||
|
||||
@@ -283,16 +237,17 @@ namespace sdbus {
|
||||
MethodCall() = default;
|
||||
|
||||
MethodReply send(uint64_t timeout) const;
|
||||
[[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout, return_slot_t) const;
|
||||
void send(void* callback, void* userData, uint64_t timeout, floating_slot_t) const;
|
||||
[[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const;
|
||||
|
||||
MethodReply createReply() const;
|
||||
MethodReply createErrorReply(const Error& error) const;
|
||||
MethodReply createErrorReply(const sdbus::Error& error) const;
|
||||
|
||||
void dontExpectReply();
|
||||
bool doesntExpectReply() const;
|
||||
|
||||
protected:
|
||||
MethodCall(void *msg, internal::IConnection* connection, adopt_message_t) noexcept;
|
||||
MethodCall(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
|
||||
|
||||
private:
|
||||
MethodReply sendWithReply(uint64_t timeout = 0) const;
|
||||
@@ -307,7 +262,6 @@ namespace sdbus {
|
||||
public:
|
||||
MethodReply() = default;
|
||||
void send() const;
|
||||
uint64_t getReplyCookie() const;
|
||||
};
|
||||
|
||||
class Signal : public Message
|
||||
@@ -318,7 +272,6 @@ namespace sdbus {
|
||||
public:
|
||||
Signal() = default;
|
||||
void setDestination(const std::string& destination);
|
||||
void setDestination(const char* destination);
|
||||
void send() const;
|
||||
};
|
||||
|
||||
@@ -350,40 +303,25 @@ namespace sdbus {
|
||||
PlainMessage() = default;
|
||||
};
|
||||
|
||||
PlainMessage createPlainMessage();
|
||||
|
||||
template <typename ...Elements>
|
||||
inline Message& Message::operator<<(const std::variant<Elements...>& value)
|
||||
{
|
||||
std::visit([this](const auto& inner)
|
||||
{
|
||||
openVariant<decltype(inner)>();
|
||||
*this << inner;
|
||||
closeVariant();
|
||||
}, value);
|
||||
|
||||
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);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename Element, std::size_t Extent>
|
||||
inline Message& Message::operator<<(const std::span<Element, Extent>& items)
|
||||
#if __cplusplus >= 202002L
|
||||
template <typename _Element, std::size_t _Extent>
|
||||
inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
|
||||
{
|
||||
serializeArray(items);
|
||||
|
||||
@@ -391,27 +329,20 @@ namespace sdbus {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Enum, typename>
|
||||
inline Message& Message::operator<<(const Enum &item)
|
||||
template <typename _Array>
|
||||
inline void Message::serializeArray(const _Array& items)
|
||||
{
|
||||
return operator<<(static_cast<std::underlying_type_t<Enum>>(item));
|
||||
}
|
||||
|
||||
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.
|
||||
if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
|
||||
appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType));
|
||||
appendArray(*signature_of<ElementType>::str().c_str(), items.data(), items.size() * sizeof(ElementType));
|
||||
}
|
||||
else
|
||||
{
|
||||
openContainer<ElementType>();
|
||||
openContainer(signature_of<ElementType>::str());
|
||||
|
||||
for (const auto& item : items)
|
||||
*this << item;
|
||||
@@ -420,131 +351,102 @@ namespace sdbus {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
inline Message& Message::operator<<(const DictEntry<Key, Value>& value)
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
|
||||
{
|
||||
openDictEntry<Key, Value>();
|
||||
*this << value.first;
|
||||
*this << value.second;
|
||||
closeDictEntry();
|
||||
serializeDictionary(items);
|
||||
|
||||
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 _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(items);
|
||||
|
||||
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 _Dictionary>
|
||||
inline void Message::serializeDictionary(const _Dictionary& items)
|
||||
{
|
||||
serializeDictionary<Key, Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using ValueType = typename _Dictionary::mapped_type;
|
||||
|
||||
return *this;
|
||||
}
|
||||
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
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& entry : dictEntries) msg << entry; });
|
||||
openContainer(arraySignature);
|
||||
|
||||
return *this;
|
||||
}
|
||||
for (const auto& item : items)
|
||||
{
|
||||
openDictEntry(dictEntrySignature);
|
||||
*this << item.first;
|
||||
*this << item.second;
|
||||
closeDictEntry();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, typename Callback>
|
||||
inline Message& Message::serializeDictionary(const Callback& callback)
|
||||
{
|
||||
openContainer<DictEntry<Key, Value>>();
|
||||
callback(*this);
|
||||
closeContainer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... Args>
|
||||
void serialize_pack(Message& msg, Args&&... args)
|
||||
template <typename... _Args>
|
||||
void serialize_pack(Message& msg, _Args&&... args)
|
||||
{
|
||||
(void)(msg << ... << std::forward<Args>(args));
|
||||
(void)(msg << ... << args);
|
||||
}
|
||||
|
||||
template <class Tuple, std::size_t... Is>
|
||||
template <class _Tuple, std::size_t... _Is>
|
||||
void serialize_tuple( Message& msg
|
||||
, const Tuple& tuple
|
||||
, std::index_sequence<Is...>)
|
||||
, const _Tuple& t
|
||||
, std::index_sequence<_Is...>)
|
||||
{
|
||||
serialize_pack(msg, std::get<Is>(tuple)...);
|
||||
serialize_pack(msg, std::get<_Is>(t)...);
|
||||
}
|
||||
} // 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...>{});
|
||||
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
|
||||
assert(structSignature.size() > 2);
|
||||
// Remove opening and closing parenthesis from the struct signature to get contents signature
|
||||
auto structContentSignature = structSignature.substr(1, structSignature.size() - 2);
|
||||
|
||||
openStruct(structContentSignature);
|
||||
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)
|
||||
{
|
||||
constexpr auto elemSignature = as_null_terminated(signature_of_v<Element>);
|
||||
if (std::strcmp(signature, elemSignature.data()) != 0)
|
||||
return false;
|
||||
|
||||
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();
|
||||
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);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename Element, std::size_t Extent>
|
||||
inline Message& Message::operator>>(std::span<Element, Extent>& items)
|
||||
#if __cplusplus >= 202002L
|
||||
template <typename _Element, std::size_t _Extent>
|
||||
inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
|
||||
{
|
||||
deserializeArray(items);
|
||||
|
||||
@@ -552,19 +454,10 @@ namespace sdbus {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Enum, typename>
|
||||
inline Message& Message::operator>>(Enum& item)
|
||||
template <typename _Array>
|
||||
inline void Message::deserializeArray(_Array& items)
|
||||
{
|
||||
std::underlying_type_t<Enum> val;
|
||||
*this >> val;
|
||||
item = static_cast<Enum>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -578,43 +471,40 @@ 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(signature_of_v<ElementType>);
|
||||
readArray(*signature.data(), reinterpret_cast<const void**>(&arrayPtr), &arraySize);
|
||||
readArray(*signature_of<ElementType>::str().c_str(), (const void**)&arrayPtr, &arraySize);
|
||||
|
||||
const size_t elementsInMsg = arraySize / sizeof(ElementType);
|
||||
const bool notEnoughSpace = items.size() < elementsInMsg;
|
||||
size_t elementsInMsg = arraySize / sizeof(ElementType);
|
||||
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(signature_of_v<Element>);
|
||||
readArray(*signature.data(), reinterpret_cast<const void**>(&arrayPtr), &arraySize);
|
||||
readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize);
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(Element)));
|
||||
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>())
|
||||
if(!enterContainer(signature_of<ElementType>::str()))
|
||||
return;
|
||||
|
||||
for (auto& elem : items)
|
||||
@@ -628,15 +518,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(signature_of<_Element>::str()))
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Element elem;
|
||||
_Element elem;
|
||||
if (*this >> elem)
|
||||
items.emplace_back(std::move(elem));
|
||||
else
|
||||
@@ -648,147 +538,94 @@ namespace sdbus {
|
||||
exitContainer();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
inline Message& Message::operator>>(DictEntry<Key, Value>& value)
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
|
||||
{
|
||||
if (!enterDictEntry<Key, Value>())
|
||||
return *this;
|
||||
*this >> value.first >> value.second;
|
||||
exitDictEntry();
|
||||
deserializeDictionary(items);
|
||||
|
||||
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 _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(items);
|
||||
|
||||
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 _Dictionary>
|
||||
inline void Message::deserializeDictionary(_Dictionary& items)
|
||||
{
|
||||
deserializeDictionary<Key, Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using ValueType = typename _Dictionary::mapped_type;
|
||||
|
||||
return *this;
|
||||
}
|
||||
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
template <typename Key, typename Value, typename Callback>
|
||||
inline Message& Message::deserializeDictionary(const Callback& callback)
|
||||
{
|
||||
if (!enterContainer<DictEntry<Key, Value>>())
|
||||
return *this;
|
||||
if (!enterContainer(arraySignature))
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
DictEntry<Key, Value> dictEntry;
|
||||
*this >> dictEntry;
|
||||
if (!*this)
|
||||
if (!enterDictEntry(dictEntrySignature))
|
||||
break;
|
||||
callback(std::move(dictEntry));
|
||||
|
||||
KeyType key;
|
||||
ValueType value;
|
||||
*this >> key >> value;
|
||||
|
||||
items.emplace(std::move(key), std::move(value));
|
||||
|
||||
exitDictEntry();
|
||||
}
|
||||
|
||||
clearFlags();
|
||||
|
||||
exitContainer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
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& tuple
|
||||
, std::index_sequence<Is...> )
|
||||
, _Tuple& t
|
||||
, std::index_sequence<_Is...> )
|
||||
{
|
||||
deserialize_pack(msg, std::get<Is>(tuple)...);
|
||||
deserialize_pack(msg, std::get<_Is>(t)...);
|
||||
}
|
||||
} // 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...>())
|
||||
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
|
||||
// Remove opening and closing parenthesis from the struct signature to get contents signature
|
||||
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
|
||||
|
||||
if (!enterStruct(structContentSignature))
|
||||
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>
|
||||
inline Message& Message::openContainer()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
|
||||
return openContainer(signature.data());
|
||||
}
|
||||
|
||||
template <typename KeyType, typename ValueType>
|
||||
inline Message& Message::openDictEntry()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<KeyType, ValueType>>);
|
||||
return openDictEntry(signature.data());
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline Message& Message::openVariant()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ValueType>);
|
||||
return openVariant(signature.data());
|
||||
}
|
||||
|
||||
template <typename... ValueTypes>
|
||||
inline Message& Message::openStruct()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<ValueTypes...>>);
|
||||
return openStruct(signature.data());
|
||||
}
|
||||
|
||||
template <typename ElementType>
|
||||
inline Message& Message::enterContainer()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
|
||||
return enterContainer(signature.data());
|
||||
}
|
||||
|
||||
template <typename KeyType, typename ValueType>
|
||||
inline Message& Message::enterDictEntry()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<KeyType, ValueType>>);
|
||||
return enterDictEntry(signature.data());
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline Message& Message::enterVariant()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ValueType>);
|
||||
return enterVariant(signature.data());
|
||||
}
|
||||
|
||||
template <typename... ValueTypes>
|
||||
inline Message& Message::enterStruct()
|
||||
{
|
||||
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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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;
|
||||
explicit Result(MethodCall call);
|
||||
Result(MethodCall call);
|
||||
|
||||
Result(const Result&) = delete;
|
||||
Result& operator=(const Result&) = delete;
|
||||
@@ -59,23 +59,21 @@ namespace sdbus {
|
||||
Result(Result&& other) = default;
|
||||
Result& operator=(Result&& other) = default;
|
||||
|
||||
~Result() = default;
|
||||
|
||||
void returnResults(const Results&... results) const;
|
||||
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();
|
||||
@@ -83,13 +81,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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ProxyInterfaces.h
|
||||
*
|
||||
@@ -29,12 +29,13 @@
|
||||
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
class IConnection;
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@@ -50,19 +51,19 @@ namespace sdbus {
|
||||
class ProxyObjectHolder
|
||||
{
|
||||
protected:
|
||||
explicit ProxyObjectHolder(std::unique_ptr<IProxy>&& proxy)
|
||||
ProxyObjectHolder(std::unique_ptr<IProxy>&& proxy)
|
||||
: proxy_(std::move(proxy))
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] const IProxy& getProxy() const
|
||||
const IProxy& getProxy() const
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
return *proxy_;
|
||||
}
|
||||
|
||||
[[nodiscard]] IProxy& getProxy()
|
||||
IProxy& getProxy()
|
||||
{
|
||||
assert(proxy_ != nullptr);
|
||||
return *proxy_;
|
||||
@@ -88,17 +89,12 @@ 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
|
||||
*
|
||||
@@ -108,9 +104,9 @@ namespace sdbus {
|
||||
* This constructor overload creates a proxy that manages its own D-Bus connection(s).
|
||||
* For more information on its behavior, consult @ref createProxy(std::string,std::string)
|
||||
*/
|
||||
ProxyInterfaces(ServiceName destination, ObjectPath objectPath)
|
||||
ProxyInterfaces(std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath)))
|
||||
, Interfaces(getProxy())...
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -123,9 +119,9 @@ namespace sdbus {
|
||||
* This constructor overload creates a proxy that manages its own D-Bus connection(s).
|
||||
* For more information on its behavior, consult @ref createProxy(std::string,std::string,sdbus::dont_run_event_loop_thread_t)
|
||||
*/
|
||||
ProxyInterfaces(ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t)
|
||||
ProxyInterfaces(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
|
||||
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
|
||||
, Interfaces(getProxy())...
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -139,9 +135,9 @@ namespace sdbus {
|
||||
* The proxy created this way just references a D-Bus connection owned and managed by the user.
|
||||
* For more information on its behavior, consult @ref createProxy(IConnection&,std::string,std::string)
|
||||
*/
|
||||
ProxyInterfaces(IConnection& connection, ServiceName destination, ObjectPath objectPath)
|
||||
ProxyInterfaces(IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(connection, std::move(destination), std::move(objectPath)))
|
||||
, Interfaces(getProxy())...
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -155,9 +151,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<IConnection>&& connection, ServiceName destination, ObjectPath objectPath)
|
||||
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath)
|
||||
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath)))
|
||||
, Interfaces(getProxy())...
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -171,9 +167,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<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<sdbus::IConnection>&& connection, std::string destination, std::string 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())...
|
||||
{
|
||||
}
|
||||
|
||||
@@ -186,7 +182,7 @@ namespace sdbus {
|
||||
*/
|
||||
void registerProxy()
|
||||
{
|
||||
(Interfaces::registerProxy(), ...);
|
||||
(_Interfaces::registerProxy(), ...);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -209,9 +205,13 @@ namespace sdbus {
|
||||
protected:
|
||||
using base_type = ProxyInterfaces;
|
||||
|
||||
ProxyInterfaces(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces(ProxyInterfaces&&) = default;
|
||||
ProxyInterfaces& operator=(ProxyInterfaces&&) = default;
|
||||
~ProxyInterfaces() = default;
|
||||
};
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_PROXYINTERFACES_H_ */
|
||||
#endif /* SDBUS_CXX_INTERFACES_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file StandardInterfaces.h
|
||||
*
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
@@ -40,14 +39,19 @@ namespace sdbus {
|
||||
// Proxy for peer
|
||||
class Peer_proxy
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Peer";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Peer";
|
||||
|
||||
protected:
|
||||
explicit Peer_proxy(IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
Peer_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Peer_proxy(const Peer_proxy&) = delete;
|
||||
Peer_proxy& operator=(const Peer_proxy&) = delete;
|
||||
Peer_proxy(Peer_proxy&&) = default;
|
||||
Peer_proxy& operator=(Peer_proxy&&) = default;
|
||||
|
||||
~Peer_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
@@ -55,38 +59,38 @@ 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);
|
||||
proxy_->callMethod("Ping").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string GetMachineId()
|
||||
{
|
||||
std::string machineUUID;
|
||||
m_proxy.callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
|
||||
proxy_->callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
|
||||
return machineUUID;
|
||||
}
|
||||
|
||||
private:
|
||||
IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for introspection
|
||||
class Introspectable_proxy
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
|
||||
|
||||
protected:
|
||||
explicit Introspectable_proxy(IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
Introspectable_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Introspectable_proxy(const Introspectable_proxy&) = delete;
|
||||
Introspectable_proxy& operator=(const Introspectable_proxy&) = delete;
|
||||
Introspectable_proxy(Introspectable_proxy&&) = default;
|
||||
Introspectable_proxy& operator=(Introspectable_proxy&&) = default;
|
||||
|
||||
~Introspectable_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
@@ -94,310 +98,163 @@ 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;
|
||||
m_proxy.callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
|
||||
proxy_->callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private:
|
||||
IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for properties
|
||||
class Properties_proxy
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
explicit Properties_proxy(IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
Properties_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Properties_proxy(const Properties_proxy&) = delete;
|
||||
Properties_proxy& operator=(const Properties_proxy&) = delete;
|
||||
Properties_proxy(Properties_proxy&&) = default;
|
||||
Properties_proxy& operator=(Properties_proxy&&) = default;
|
||||
|
||||
~Properties_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
m_proxy
|
||||
.uponSignal("PropertiesChanged")
|
||||
proxy_
|
||||
->uponSignal("PropertiesChanged")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const InterfaceName& interfaceName
|
||||
, const std::map<PropertyName, Variant>& changedProperties
|
||||
, const std::vector<PropertyName>& invalidatedProperties )
|
||||
.call([this]( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties )
|
||||
{
|
||||
this->onPropertiesChanged(interfaceName, changedProperties, invalidatedProperties);
|
||||
});
|
||||
}
|
||||
|
||||
virtual void onPropertiesChanged( const InterfaceName& interfaceName
|
||||
, const std::map<PropertyName, Variant>& changedProperties
|
||||
, const std::vector<PropertyName>& invalidatedProperties ) = 0;
|
||||
virtual void onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties ) = 0;
|
||||
|
||||
public:
|
||||
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)
|
||||
sdbus::Variant Get(const std::string& interfaceName, const std::string& propertyName)
|
||||
{
|
||||
return m_proxy.getProperty(propertyName).onInterface(interfaceName);
|
||||
return proxy_->getProperty(propertyName).onInterface(interfaceName);
|
||||
}
|
||||
|
||||
Variant Get(std::string_view interfaceName, std::string_view propertyName)
|
||||
template <typename _Function>
|
||||
PendingAsyncCall GetAsync(const std::string& interfaceName, const std::string& propertyName, _Function&& callback)
|
||||
{
|
||||
return m_proxy.getProperty(propertyName).onInterface(interfaceName);
|
||||
return proxy_->getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
PendingAsyncCall GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, Function&& callback)
|
||||
std::future<sdbus::Variant> GetAsync(const std::string& interfaceName, const std::string& propertyName, with_future_t)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
|
||||
return proxy_->getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
[[nodiscard]] Slot GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, Function&& callback, return_slot_t)
|
||||
void Set(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value);
|
||||
}
|
||||
|
||||
std::future<Variant> GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_future_t)
|
||||
void Set(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, dont_expect_reply_t)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
|
||||
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply);
|
||||
}
|
||||
|
||||
Awaitable<Variant> GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_awaitable_t)
|
||||
template <typename _Function>
|
||||
PendingAsyncCall SetAsync(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, _Function&& callback)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsAwaitable();
|
||||
return proxy_->setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
PendingAsyncCall GetAsync(std::string_view interfaceName, std::string_view propertyName, Function&& callback)
|
||||
std::future<void> SetAsync(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value, with_future_t)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
|
||||
return proxy_->setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture();
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
[[nodiscard]] Slot GetAsync(std::string_view interfaceName, std::string_view propertyName, Function&& callback, return_slot_t)
|
||||
std::map<std::string, sdbus::Variant> GetAll(const std::string& interfaceName)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
return proxy_->getAllProperties().onInterface(interfaceName);
|
||||
}
|
||||
|
||||
std::future<Variant> GetAsync(std::string_view interfaceName, std::string_view propertyName, with_future_t)
|
||||
template <typename _Function>
|
||||
PendingAsyncCall GetAllAsync(const std::string& interfaceName, _Function&& callback)
|
||||
{
|
||||
return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture();
|
||||
return proxy_->getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback));
|
||||
}
|
||||
|
||||
Awaitable<Variant> GetAsync(std::string_view interfaceName, std::string_view propertyName, with_awaitable_t)
|
||||
std::future<std::map<std::string, sdbus::Variant>> GetAllAsync(const std::string& interfaceName, with_future_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 Variant& value)
|
||||
{
|
||||
m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value);
|
||||
}
|
||||
|
||||
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 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 Variant& value, 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 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(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, with_future_t)
|
||||
{
|
||||
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture();
|
||||
}
|
||||
|
||||
Awaitable<void> SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const Variant& value, with_awaitable_t)
|
||||
{
|
||||
return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsAwaitable();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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, Variant> GetAll(std::string_view interfaceName)
|
||||
{
|
||||
return m_proxy.getAllProperties().onInterface(interfaceName);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
PendingAsyncCall GetAllAsync(const InterfaceName& interfaceName, 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)
|
||||
{
|
||||
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
}
|
||||
|
||||
std::future<std::map<PropertyName, Variant>> GetAllAsync(const InterfaceName& interfaceName, with_future_t)
|
||||
{
|
||||
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture();
|
||||
}
|
||||
|
||||
Awaitable<std::map<PropertyName, Variant>> GetAllAsync(const InterfaceName& interfaceName, with_awaitable_t)
|
||||
{
|
||||
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsAwaitable();
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
PendingAsyncCall GetAllAsync(std::string_view interfaceName, Function&& callback)
|
||||
{
|
||||
return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<Function>(callback));
|
||||
}
|
||||
|
||||
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();
|
||||
return proxy_->getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture();
|
||||
}
|
||||
|
||||
private:
|
||||
IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for object manager
|
||||
class ObjectManager_proxy
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_proxy(IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
ObjectManager_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy(ObjectManager_proxy&&) = default;
|
||||
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default;
|
||||
|
||||
~ObjectManager_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
m_proxy
|
||||
.uponSignal("InterfacesAdded")
|
||||
proxy_
|
||||
->uponSignal("InterfacesAdded")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const ObjectPath& objectPath
|
||||
, const std::map<InterfaceName, std::map<PropertyName, Variant>>& interfacesAndProperties )
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
{
|
||||
this->onInterfacesAdded(objectPath, interfacesAndProperties);
|
||||
});
|
||||
|
||||
m_proxy
|
||||
.uponSignal("InterfacesRemoved")
|
||||
proxy_->uponSignal("InterfacesRemoved")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces )
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
this->onInterfacesRemoved(objectPath, interfaces);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) = 0;
|
||||
virtual void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<std::string>& interfaces) = 0;
|
||||
|
||||
public:
|
||||
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<std::string, std::map<std::string, sdbus::Variant>>> GetManagedObjects()
|
||||
{
|
||||
std::map<ObjectPath, std::map<InterfaceName, std::map<PropertyName, Variant>>> objectsInterfacesAndProperties;
|
||||
m_proxy.callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
|
||||
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
|
||||
proxy_->callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
|
||||
return objectsInterfacesAndProperties;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
PendingAsyncCall GetManagedObjectsAsync(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)
|
||||
{
|
||||
return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<Function>(callback), return_slot);
|
||||
}
|
||||
|
||||
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<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:
|
||||
IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Adaptors for the above-listed standard D-Bus interfaces are not necessary because the functionality
|
||||
@@ -407,13 +264,18 @@ namespace sdbus {
|
||||
// Adaptor for properties
|
||||
class Properties_adaptor
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
explicit Properties_adaptor(IObject& object) : m_object(object)
|
||||
Properties_adaptor(sdbus::IObject& object) : object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
Properties_adaptor(const Properties_adaptor&) = delete;
|
||||
Properties_adaptor& operator=(const Properties_adaptor&) = delete;
|
||||
Properties_adaptor(Properties_adaptor&&) = default;
|
||||
Properties_adaptor& operator=(Properties_adaptor&&) = default;
|
||||
|
||||
~Properties_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
@@ -421,39 +283,24 @@ 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)
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& properties)
|
||||
{
|
||||
m_object.emitPropertiesChangedSignal(interfaceName, properties);
|
||||
object_->emitPropertiesChangedSignal(interfaceName, properties);
|
||||
}
|
||||
|
||||
void emitPropertiesChangedSignal(const char* interfaceName, const std::vector<PropertyName>& properties)
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName)
|
||||
{
|
||||
m_object.emitPropertiesChangedSignal(interfaceName, properties);
|
||||
}
|
||||
|
||||
void emitPropertiesChangedSignal(const InterfaceName& interfaceName)
|
||||
{
|
||||
m_object.emitPropertiesChangedSignal(interfaceName);
|
||||
}
|
||||
|
||||
void emitPropertiesChangedSignal(const char* interfaceName)
|
||||
{
|
||||
m_object.emitPropertiesChangedSignal(interfaceName);
|
||||
object_->emitPropertiesChangedSignal(interfaceName);
|
||||
}
|
||||
|
||||
private:
|
||||
IObject& m_object;
|
||||
sdbus::IObject* 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.
|
||||
*
|
||||
@@ -462,49 +309,53 @@ namespace sdbus {
|
||||
*/
|
||||
class ObjectManager_adaptor
|
||||
{
|
||||
static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_adaptor(IObject& object) : m_object(object)
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object) : object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
|
||||
ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete;
|
||||
ObjectManager_adaptor(ObjectManager_adaptor&&) = default;
|
||||
ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = default;
|
||||
|
||||
~ObjectManager_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addObjectManager();
|
||||
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:
|
||||
IObject& m_object;
|
||||
sdbus::IObject* 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 its 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 it's 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(IObject& object)
|
||||
: m_object(object)
|
||||
explicit ManagedObject_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
ManagedObject_adaptor(const ManagedObject_adaptor&) = delete;
|
||||
ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete;
|
||||
ManagedObject_adaptor(ManagedObject_adaptor&&) = default;
|
||||
ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = default;
|
||||
|
||||
~ManagedObject_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
@@ -512,11 +363,6 @@ 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
|
||||
*
|
||||
@@ -524,7 +370,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesAddedSignal()
|
||||
{
|
||||
m_object.emitInterfacesAddedSignal();
|
||||
object_->emitInterfacesAddedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -532,9 +378,9 @@ namespace sdbus {
|
||||
*
|
||||
* See IObject::emitInterfacesAddedSignal().
|
||||
*/
|
||||
void emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces)
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
m_object.emitInterfacesAddedSignal(interfaces);
|
||||
object_->emitInterfacesAddedSignal(interfaces);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -544,7 +390,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesRemovedSignal()
|
||||
{
|
||||
m_object.emitInterfacesRemovedSignal();
|
||||
object_->emitInterfacesRemovedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -552,15 +398,15 @@ namespace sdbus {
|
||||
*
|
||||
* See IObject::emitInterfacesRemovedSignal().
|
||||
*/
|
||||
void emitInterfacesRemovedSignal(const std::vector<InterfaceName>& interfaces)
|
||||
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
m_object.emitInterfacesRemovedSignal(interfaces);
|
||||
object_->emitInterfacesRemovedSignal(interfaces);
|
||||
}
|
||||
|
||||
private:
|
||||
IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_STANDARDINTERFACES_H_ */
|
||||
|
||||
+344
-343
File diff suppressed because it is too large
Load Diff
+67
-374
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types.h
|
||||
*
|
||||
@@ -30,12 +30,11 @@
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace sdbus {
|
||||
@@ -49,7 +48,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
|
||||
@@ -57,91 +56,48 @@ namespace sdbus {
|
||||
public:
|
||||
Variant();
|
||||
|
||||
template <typename ValueType>
|
||||
explicit Variant(const ValueType& value) : Variant()
|
||||
{
|
||||
msg_.openVariant<ValueType>();
|
||||
msg_ << value;
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
Variant(const Variant& value, embed_variant_t) : Variant()
|
||||
{
|
||||
msg_.openVariant<Variant>();
|
||||
msg_ << value;
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename Struct>
|
||||
explicit Variant(const as_dictionary<Struct>& value) : Variant()
|
||||
{
|
||||
msg_.openVariant<std::map<std::string, Variant>>();
|
||||
msg_ << as_dictionary(value.m_struct);
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename... Elements>
|
||||
Variant(const std::variant<Elements...>& value) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions): implicit conversion intentional
|
||||
template <typename _ValueType>
|
||||
explicit Variant(const _ValueType& value)
|
||||
: Variant()
|
||||
{
|
||||
msg_.openVariant(signature_of<_ValueType>::str());
|
||||
msg_ << value;
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType get() const
|
||||
template <typename _ValueType>
|
||||
_ValueType get() const
|
||||
{
|
||||
_ValueType val;
|
||||
msg_.rewind(false);
|
||||
|
||||
msg_.enterVariant<ValueType>();
|
||||
ValueType val;
|
||||
msg_.enterVariant(signature_of<_ValueType>::str());
|
||||
msg_ >> val;
|
||||
msg_.exitVariant();
|
||||
return val;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string dumpToString() const
|
||||
{
|
||||
msg_.rewind(false);
|
||||
|
||||
return msg_.dumpToString(Message::DumpFlags::SubtreeOnly);
|
||||
}
|
||||
|
||||
// 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
|
||||
template <typename _ValueType, typename = std::enable_if_t<signature_of<_ValueType>::is_valid>>
|
||||
operator _ValueType() const
|
||||
{
|
||||
return get<ValueType>();
|
||||
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>);
|
||||
return std::strcmp(signature.data(), peekValueType()) == 0;
|
||||
return signature_of<_Type>::str() == peekValueType();
|
||||
}
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
void serializeTo(Message& msg) const;
|
||||
void deserializeFrom(Message& msg);
|
||||
const char* peekValueType() const;
|
||||
std::string peekValueType() const;
|
||||
|
||||
private:
|
||||
mutable PlainMessage msg_;
|
||||
mutable PlainMessage msg_{};
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
@@ -154,154 +110,86 @@ 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;
|
||||
|
||||
// Disable constructor if an older then 7.1.0 version of GCC is used
|
||||
#if !((defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !(__GNUC__ > 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 0)))))
|
||||
Struct() = default;
|
||||
|
||||
explicit Struct(const std::tuple<ValueTypes...>& tuple)
|
||||
: std::tuple<ValueTypes...>(tuple)
|
||||
explicit Struct(const std::tuple<_ValueTypes...>& t)
|
||||
: std::tuple<_ValueTypes...>(t)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
template <std::size_t I>
|
||||
[[nodiscard]] auto& get()
|
||||
template <std::size_t _I>
|
||||
auto& get()
|
||||
{
|
||||
return std::get<I>(*this);
|
||||
return std::get<_I>(*this);
|
||||
}
|
||||
|
||||
template <std::size_t I>
|
||||
[[nodiscard]] const auto& get() const
|
||||
template <std::size_t _I>
|
||||
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>
|
||||
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)
|
||||
template<typename... _Elements>
|
||||
constexpr Struct<std::decay_t<_Elements>...>
|
||||
make_struct(_Elements&&... args)
|
||||
{
|
||||
using result_type = Struct<std::decay_t<Elements>...>;
|
||||
return result_type(std::forward<Elements>(args)...);
|
||||
typedef Struct<std::decay_t<_Elements>...> result_type;
|
||||
return result_type(std::forward<_Elements>(args)...);
|
||||
}
|
||||
|
||||
/********************************************//**
|
||||
* @class ObjectPath
|
||||
*
|
||||
* Strong type representing the D-Bus object path
|
||||
* Representation of object path D-Bus type
|
||||
*
|
||||
***********************************************/
|
||||
class ObjectPath : public std::string
|
||||
{
|
||||
public:
|
||||
ObjectPath() = default;
|
||||
explicit ObjectPath(std::string value)
|
||||
: std::string(std::move(value))
|
||||
using std::string::string;
|
||||
ObjectPath() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
|
||||
ObjectPath(const ObjectPath&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
|
||||
ObjectPath(ObjectPath&&) = default; // Enable move - user-declared copy ctor prevents implicit creation
|
||||
ObjectPath& operator = (const ObjectPath&) = default; // Fixes gcc 8.3 error (deleted copy assignment)
|
||||
ObjectPath& operator = (ObjectPath&&) = default; // Enable move - user-declared copy assign prevents implicit creation
|
||||
ObjectPath(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
explicit ObjectPath(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class BusName
|
||||
*
|
||||
* Strong type representing the D-Bus bus/service/connection name
|
||||
*
|
||||
***********************************************/
|
||||
class BusName : public std::string
|
||||
{
|
||||
public:
|
||||
BusName() = default;
|
||||
explicit BusName(std::string value)
|
||||
: std::string(std::move(value))
|
||||
{}
|
||||
explicit BusName(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
using ServiceName = BusName;
|
||||
using ConnectionName = BusName;
|
||||
|
||||
/********************************************//**
|
||||
* @class InterfaceName
|
||||
*
|
||||
* Strong type representing the D-Bus interface name
|
||||
*
|
||||
***********************************************/
|
||||
class InterfaceName : public std::string
|
||||
{
|
||||
public:
|
||||
InterfaceName() = default;
|
||||
explicit InterfaceName(std::string value)
|
||||
: std::string(std::move(value))
|
||||
{}
|
||||
explicit InterfaceName(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @class MemberName
|
||||
*
|
||||
* Strong type representing the D-Bus member name
|
||||
*
|
||||
***********************************************/
|
||||
class MemberName : public std::string
|
||||
{
|
||||
public:
|
||||
MemberName() = default;
|
||||
explicit MemberName(std::string value)
|
||||
: std::string(std::move(value))
|
||||
{}
|
||||
explicit MemberName(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
using MethodName = MemberName;
|
||||
using SignalName = MemberName;
|
||||
using PropertyName = MemberName;
|
||||
|
||||
/********************************************//**
|
||||
* @class Signature
|
||||
*
|
||||
* Strong type representing the D-Bus object path
|
||||
* Representation of Signature D-Bus type
|
||||
*
|
||||
***********************************************/
|
||||
class Signature : public std::string
|
||||
{
|
||||
public:
|
||||
Signature() = default;
|
||||
explicit Signature(std::string value)
|
||||
: std::string(std::move(value))
|
||||
using std::string::string;
|
||||
Signature() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
|
||||
Signature(const Signature&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
|
||||
Signature(Signature&&) = default; // Enable move - user-declared copy ctor prevents implicit creation
|
||||
Signature& operator = (const Signature&) = default; // Fixes gcc 8.3 error (deleted copy assignment)
|
||||
Signature& operator = (Signature&&) = default; // Enable move - user-declared copy assign prevents implicit creation
|
||||
Signature(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
explicit Signature(const char* value)
|
||||
: std::string(value)
|
||||
{}
|
||||
|
||||
using std::string::operator=;
|
||||
};
|
||||
|
||||
@@ -347,12 +235,12 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnixFd(UnixFd&& other) noexcept
|
||||
UnixFd(UnixFd&& other)
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
UnixFd& operator=(UnixFd&& other) noexcept
|
||||
UnixFd& operator=(UnixFd&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
{
|
||||
@@ -404,211 +292,16 @@ namespace sdbus {
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @typedef DictEntry
|
||||
*
|
||||
* DictEntry is implemented as std::pair, a standard
|
||||
* value_type in STL(-like) associative containers.
|
||||
*
|
||||
***********************************************/
|
||||
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...>> // 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...>> // NOLINT(cert-dcl58-cpp): specialization in std namespace allowed in this case
|
||||
: std::tuple_size<std::tuple<ValueTypes...>>
|
||||
template <size_t _I, typename... _ValueTypes>
|
||||
struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>>
|
||||
: std::tuple_element<_I, std::tuple<_ValueTypes...>>
|
||||
{};
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
|
||||
/********************************************//**
|
||||
* @name SDBUSCPP_REGISTER_STRUCT
|
||||
*
|
||||
* A convenient way to extend sdbus-c++ type system with user-defined structs.
|
||||
*
|
||||
* The macro teaches sdbus-c++ to recognize the user-defined struct
|
||||
* as a valid C++ representation of a D-Bus Struct type, and enables
|
||||
* clients to use their struct conveniently instead of the (too
|
||||
* generic and less expressive) `sdbus::Struct<...>` in sdbus-c++ API.
|
||||
*
|
||||
* It also enables to serialize a user-defined struct as an a{sv} dictionary,
|
||||
* and to deserialize an a{sv} dictionary into the user-defined struct.
|
||||
*
|
||||
* The first argument is the struct type name and the remaining arguments
|
||||
* are names of struct members. Members must be of types supported by
|
||||
* sdbus-c++ (or of user-defined types that sdbus-c++ was taught to support).
|
||||
* Members can be other structs (nesting is supported).
|
||||
* The macro must be placed in the global namespace.
|
||||
*
|
||||
* For example, given the user-defined struct `ABC`:
|
||||
*
|
||||
* namespace foo {
|
||||
* struct ABC
|
||||
* {
|
||||
* int number;
|
||||
* std::string name;
|
||||
* std::vector<double> data;
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* one can teach sdbus-c++ about the contents of this struct simply with:
|
||||
*
|
||||
* SDBUSCPP_REGISTER_STRUCT(foo::ABC, number, name, data);
|
||||
*
|
||||
* Up to 16 struct members are supported by the macro.
|
||||
*
|
||||
***********************************************/
|
||||
#define SDBUSCPP_REGISTER_STRUCT(STRUCT, ...) \
|
||||
namespace sdbus { \
|
||||
static_assert(SDBUSCPP_PP_NARG(__VA_ARGS__) <= 16, \
|
||||
"Not more than 16 struct members are supported, please open an issue if you need more"); \
|
||||
\
|
||||
template <> \
|
||||
struct signature_of<STRUCT> \
|
||||
: signature_of<Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
|
||||
{}; \
|
||||
\
|
||||
inline auto as_dictionary_if_struct(const STRUCT& object) \
|
||||
{ \
|
||||
return as_dictionary<STRUCT>(object); \
|
||||
} \
|
||||
\
|
||||
inline Message& operator<<(Message& msg, const STRUCT& items) \
|
||||
{ \
|
||||
return msg << Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
|
||||
} \
|
||||
\
|
||||
inline Message& operator<<(Message& msg, const as_dictionary<STRUCT>& s) \
|
||||
{ \
|
||||
if constexpr (!nested_struct_as_dict_serialization_v<STRUCT>) \
|
||||
return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
|
||||
else \
|
||||
return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
|
||||
} \
|
||||
\
|
||||
inline Message& operator>>(Message& msg, STRUCT& s) \
|
||||
{ \
|
||||
/* First, try to deserialize as a struct */ \
|
||||
if (msg.peekType().first == signature_of<STRUCT>::type_value) \
|
||||
{ \
|
||||
Struct sdbusStruct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(s, __VA_ARGS__))}; \
|
||||
return msg >> sdbusStruct; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise try to deserialize as a dictionary of strings to variants */ \
|
||||
\
|
||||
return msg.deserializeDictionary<std::string, Variant>([&s](const auto& dictEntry) \
|
||||
{ \
|
||||
const std::string& key = dictEntry.first; /* Intentionally not using structured bindings */ \
|
||||
const Variant& value = dictEntry.second; \
|
||||
\
|
||||
using namespace std::string_literals; \
|
||||
/* This also handles members which are structs serialized as dict of strings to variants, recursively */ \
|
||||
SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(s, __VA_ARGS__) \
|
||||
SDBUS_THROW_ERROR_IF( strict_dict_as_struct_deserialization_v<STRUCT> \
|
||||
, ("Failed to deserialize struct from a dictionary: could not find field '"s += key) += "' in struct 'my::Struct'" \
|
||||
, EINVAL ); \
|
||||
}); \
|
||||
} \
|
||||
} \
|
||||
/**/
|
||||
|
||||
/********************************************//**
|
||||
* @name SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION
|
||||
*
|
||||
* Enables relaxed deserialization of an a{sv} dictionary into a user-defined struct STRUCT.
|
||||
*
|
||||
* The default (strict) deserialization mode is that if there are entries in the dictionary
|
||||
* which do not have a corresponding field in the struct, an exception is thrown.
|
||||
* In the relaxed mode, such entries are silently skipped.
|
||||
*
|
||||
* The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro,
|
||||
* and must be placed before SDBUSCPP_REGISTER_STRUCT macro.
|
||||
***********************************************/
|
||||
#define SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(STRUCT) \
|
||||
template <> \
|
||||
constexpr auto sdbus::strict_dict_as_struct_deserialization_v<STRUCT> = false; \
|
||||
/**/
|
||||
|
||||
/********************************************//**
|
||||
* @name SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION
|
||||
*
|
||||
* Enables nested serialization of user-defined struct STRUCT as an a{sv} dictionary.
|
||||
*
|
||||
* By default, STRUCT fields which are structs themselves are serialized as D-Bus structs.
|
||||
* This macro tells sdbus-c++ to also serialize nested structs, in a recursive fashion,
|
||||
* as a{sv} dictionaries.
|
||||
*
|
||||
* The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro,
|
||||
* and must be placed before SDBUSCPP_REGISTER_STRUCT macro.
|
||||
***********************************************/
|
||||
#define SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(STRUCT) \
|
||||
template <> \
|
||||
constexpr auto sdbus::nested_struct_as_dict_serialization_v<STRUCT> = true \
|
||||
/**/
|
||||
|
||||
/*!
|
||||
* @cond SDBUSCPP_INTERNAL
|
||||
*
|
||||
* Internal helper preprocessor facilities
|
||||
*/
|
||||
#define SDBUSCPP_STRUCT_MEMBERS(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER(STRUCT, MEMBER) STRUCT.MEMBER
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_TYPE, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPE(STRUCT, MEMBER) decltype(STRUCT::MEMBER)
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{STRUCT.MEMBER}}
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{as_dictionary_if_struct(STRUCT.MEMBER)}}
|
||||
|
||||
#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER, SDBUSCPP_PP_SPACE, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER(STRUCT, MEMBER) if (key == #MEMBER) STRUCT.MEMBER = value.get<decltype(STRUCT.MEMBER)>(); else
|
||||
|
||||
#define SDBUSCPP_FOR_EACH_1(M, D, S, M1) M(S, M1)
|
||||
#define SDBUSCPP_FOR_EACH_2(M, D, S, M1, M2) M(S, M1) D M(S, M2)
|
||||
#define SDBUSCPP_FOR_EACH_3(M, D, S, M1, M2, M3) M(S, M1) D M(S, M2) D M(S, M3)
|
||||
#define SDBUSCPP_FOR_EACH_4(M, D, S, M1, M2, M3, M4) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4)
|
||||
#define SDBUSCPP_FOR_EACH_5(M, D, S, M1, M2, M3, M4, M5) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5)
|
||||
#define SDBUSCPP_FOR_EACH_6(M, D, S, M1, M2, M3, M4, M5, M6) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6)
|
||||
#define SDBUSCPP_FOR_EACH_7(M, D, S, M1, M2, M3, M4, M5, M6, M7) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7)
|
||||
#define SDBUSCPP_FOR_EACH_8(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8)
|
||||
#define SDBUSCPP_FOR_EACH_9(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9)
|
||||
#define SDBUSCPP_FOR_EACH_10(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10)
|
||||
#define SDBUSCPP_FOR_EACH_11(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11)
|
||||
#define SDBUSCPP_FOR_EACH_12(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12)
|
||||
#define SDBUSCPP_FOR_EACH_13(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13)
|
||||
#define SDBUSCPP_FOR_EACH_14(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14)
|
||||
#define SDBUSCPP_FOR_EACH_15(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15)
|
||||
#define SDBUSCPP_FOR_EACH_16(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15) D M(S, M16)
|
||||
|
||||
#define SDBUSCPP_PP_CAT(X, Y) SDBUSCPP_PP_CAT_IMPL(X, Y)
|
||||
#define SDBUSCPP_PP_CAT_IMPL(X, Y) X##Y
|
||||
#define SDBUSCPP_PP_NARG(...) SDBUSCPP_PP_NARG_IMPL(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define SDBUSCPP_PP_NARG_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _N, ...) _N
|
||||
|
||||
#define SDBUSCPP_PP_COMMA ,
|
||||
#define SDBUSCPP_PP_SPACE
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
template <typename... _ValueTypes>
|
||||
struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
|
||||
: std::tuple_size<std::tuple<_ValueTypes...>>
|
||||
{};
|
||||
|
||||
#endif /* SDBUS_CXX_TYPES_H_ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2023 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableItems.h
|
||||
*
|
||||
@@ -27,7 +27,6 @@
|
||||
#define SDBUS_CXX_VTABLEITEMS_H_
|
||||
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
|
||||
#include <string>
|
||||
@@ -38,59 +37,56 @@ namespace sdbus {
|
||||
|
||||
struct MethodVTableItem
|
||||
{
|
||||
template <typename Function> MethodVTableItem& implementedAs(Function&& callback);
|
||||
template <typename _Function> MethodVTableItem& implementedAs(_Function&& callback);
|
||||
MethodVTableItem& withInputParamNames(std::vector<std::string> names);
|
||||
template <typename... String> MethodVTableItem& withInputParamNames(String... names);
|
||||
template <typename... _String> MethodVTableItem& withInputParamNames(_String... names);
|
||||
MethodVTableItem& withOutputParamNames(std::vector<std::string> names);
|
||||
template <typename... String> MethodVTableItem& withOutputParamNames(String... names);
|
||||
template <typename... _String> MethodVTableItem& withOutputParamNames(_String... names);
|
||||
MethodVTableItem& markAsDeprecated();
|
||||
MethodVTableItem& markAsPrivileged();
|
||||
MethodVTableItem& withNoReply();
|
||||
|
||||
MethodName name;
|
||||
Signature inputSignature;
|
||||
std::string name;
|
||||
std::string inputSignature;
|
||||
std::vector<std::string> inputParamNames;
|
||||
Signature outputSignature;
|
||||
std::string outputSignature;
|
||||
std::vector<std::string> outputParamNames;
|
||||
method_callback callbackHandler;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
MethodVTableItem registerMethod(MethodName methodName);
|
||||
MethodVTableItem registerMethod(std::string methodName);
|
||||
|
||||
struct SignalVTableItem
|
||||
{
|
||||
template <typename... Args> SignalVTableItem& withParameters();
|
||||
template <typename... Args> SignalVTableItem& withParameters(std::vector<std::string> names);
|
||||
template <typename... Args, typename... String> SignalVTableItem& withParameters(String... names);
|
||||
template <typename... _Args> SignalVTableItem& withParameters();
|
||||
template <typename... _Args> SignalVTableItem& withParameters(std::vector<std::string> names);
|
||||
template <typename... _Args, typename... _String> SignalVTableItem& withParameters(_String... names);
|
||||
SignalVTableItem& markAsDeprecated();
|
||||
|
||||
SignalName name;
|
||||
Signature signature;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::vector<std::string> paramNames;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
SignalVTableItem registerSignal(SignalName signalName);
|
||||
SignalVTableItem registerSignal(std::string signalName);
|
||||
|
||||
struct PropertyVTableItem
|
||||
{
|
||||
template <typename Function> PropertyVTableItem& withGetter(Function&& callback);
|
||||
template <typename Function> PropertyVTableItem& withSetter(Function&& callback);
|
||||
template <typename _Function> PropertyVTableItem& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyVTableItem& withSetter(_Function&& callback);
|
||||
PropertyVTableItem& markAsDeprecated();
|
||||
PropertyVTableItem& markAsPrivileged();
|
||||
PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
PropertyName name;
|
||||
Signature signature;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
property_get_callback getter;
|
||||
property_set_callback setter;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
PropertyVTableItem registerProperty(PropertyName propertyName);
|
||||
PropertyVTableItem registerProperty(std::string propertyName);
|
||||
|
||||
struct InterfaceFlagsVTableItem
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2023 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<_Function>::str();
|
||||
outputSignature = signature_of_function_output_arguments<_Function>::str();
|
||||
callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<Function> inputArgs;
|
||||
tuple_of_function_input_arg_types_t<_Function> inputArgs;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple.
|
||||
call >> inputArgs;
|
||||
|
||||
if constexpr (!is_async_method_v<Function>)
|
||||
if constexpr (!is_async_method_v<_Function>)
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
auto ret = sdbus::apply(callback, inputArgs);
|
||||
@@ -66,7 +66,7 @@ namespace sdbus {
|
||||
else
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple and with result object to be set later
|
||||
using AsyncResult = typename function_traits<Function>::async_result_t;
|
||||
using AsyncResult = typename function_traits<_Function>::async_result_t;
|
||||
sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs));
|
||||
}
|
||||
};
|
||||
@@ -81,10 +81,10 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... String>
|
||||
inline MethodVTableItem& MethodVTableItem::withInputParamNames(String... names)
|
||||
template <typename... _String>
|
||||
inline MethodVTableItem& MethodVTableItem::withInputParamNames(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withInputParamNames({names...});
|
||||
}
|
||||
@@ -96,10 +96,10 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... String>
|
||||
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(String... names)
|
||||
template <typename... _String>
|
||||
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withOutputParamNames({names...});
|
||||
}
|
||||
@@ -125,43 +125,38 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodVTableItem registerMethod(MethodName methodName)
|
||||
{
|
||||
return {std::move(methodName), {}, {}, {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
inline MethodVTableItem registerMethod(std::string methodName)
|
||||
{
|
||||
return registerMethod(MethodName{std::move(methodName)});
|
||||
return {std::move(methodName), {}, {}, {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** Signal VTable Item ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
template <typename... Args>
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters()
|
||||
{
|
||||
signature = signature_of_function_input_arguments_v<void(Args...)>;
|
||||
signature = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(std::vector<std::string> names)
|
||||
{
|
||||
paramNames = std::move(names);
|
||||
|
||||
return withParameters<Args...>();
|
||||
return withParameters<_Args...>();
|
||||
}
|
||||
|
||||
template <typename... Args, typename... String>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(String... names)
|
||||
template <typename... _Args, typename... _String>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
static_assert(sizeof...(Args) == sizeof...(String), "Numbers of signal parameters and their names don't match");
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
static_assert(sizeof...(_Args) == sizeof...(_String), "Numbers of signal parameters and their names don't match");
|
||||
|
||||
return withParameters<Args...>({names...});
|
||||
return withParameters<_Args...>({names...});
|
||||
}
|
||||
|
||||
inline SignalVTableItem& SignalVTableItem::markAsDeprecated()
|
||||
@@ -171,30 +166,25 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SignalVTableItem registerSignal(SignalName signalName)
|
||||
{
|
||||
return {std::move(signalName), {}, {}, {}};
|
||||
}
|
||||
|
||||
inline SignalVTableItem registerSignal(std::string signalName)
|
||||
{
|
||||
return registerSignal(SignalName{std::move(signalName)});
|
||||
return {std::move(signalName), {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** 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_v<function_result_t<Function>>, "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<function_result_t<_Function>>::value, "Property getter function must return property value");
|
||||
|
||||
if (signature.empty())
|
||||
signature = signature_of_function_output_arguments_v<Function>;
|
||||
signature = signature_of_function_output_arguments<_Function>::str();
|
||||
|
||||
getter = [callback = std::forward<Function>(callback)](PropertyGetReply& reply)
|
||||
getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
|
||||
{
|
||||
// Get the propety value and serialize it into the pre-constructed reply message
|
||||
reply << callback();
|
||||
@@ -203,19 +193,19 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline PropertyVTableItem& PropertyVTableItem::withSetter(Function&& callback)
|
||||
template <typename _Function>
|
||||
inline PropertyVTableItem& PropertyVTableItem::withSetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_argument_count_v<Function> == 1, "Property setter function must take one parameter - the property value");
|
||||
static_assert(std::is_void_v<function_result_t<Function>>, "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<function_result_t<_Function>>::value, "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<_Function>::str();
|
||||
|
||||
setter = [callback = std::forward<Function>(callback)](PropertySetCall call)
|
||||
setter = [callback = std::forward<_Function>(callback)](PropertySetCall call)
|
||||
{
|
||||
// Default-construct property value
|
||||
using property_type = function_argument_t<Function, 0>;
|
||||
using property_type = function_argument_t<_Function, 0>;
|
||||
std::decay_t<property_type> property;
|
||||
|
||||
// Deserialize property value from the incoming call message
|
||||
@@ -249,14 +239,9 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyVTableItem registerProperty(PropertyName propertyName)
|
||||
{
|
||||
return {std::move(propertyName), {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
inline PropertyVTableItem registerProperty(std::string propertyName)
|
||||
{
|
||||
return registerProperty(PropertyName{std::move(propertyName)});
|
||||
return {std::move(propertyName), {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** --------------------------- ***/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file sdbus-c++.h
|
||||
*
|
||||
@@ -24,7 +24,6 @@
|
||||
* 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>
|
||||
@@ -37,4 +36,3 @@
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
+195
-308
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection.cpp
|
||||
*
|
||||
@@ -27,34 +27,20 @@
|
||||
#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 {
|
||||
|
||||
@@ -118,23 +104,13 @@ 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)
|
||||
void Connection::requestName(const std::string& name)
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(name.c_str());
|
||||
SDBUS_CHECK_SERVICE_NAME(name);
|
||||
|
||||
auto r = sdbus_->sd_bus_request_name(bus_.get(), name.c_str(), 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
|
||||
@@ -144,7 +120,7 @@ void Connection::requestName(const ServiceName& name)
|
||||
wakeUpEventLoopIfMessagesInQueue();
|
||||
}
|
||||
|
||||
void Connection::releaseName(const ServiceName& name)
|
||||
void Connection::releaseName(const std::string& name)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_release_name(bus_.get(), name.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
|
||||
@@ -154,12 +130,12 @@ void Connection::releaseName(const ServiceName& name)
|
||||
wakeUpEventLoopIfMessagesInQueue();
|
||||
}
|
||||
|
||||
BusName Connection::getUniqueName() const
|
||||
std::string Connection::getUniqueName() const
|
||||
{
|
||||
const char* name{};
|
||||
auto r = sdbus_->sd_bus_get_unique_name(bus_.get(), &name);
|
||||
SDBUS_THROW_ERROR_IF(r < 0 || name == nullptr, "Failed to get unique bus name", -r);
|
||||
return BusName{name};
|
||||
const char* unique = nullptr;
|
||||
auto r = sdbus_->sd_bus_get_unique_name(bus_.get(), &unique);
|
||||
SDBUS_THROW_ERROR_IF(r < 0 || unique == nullptr, "Failed to get unique bus name", -r);
|
||||
return unique;
|
||||
}
|
||||
|
||||
void Connection::enterEventLoop()
|
||||
@@ -202,14 +178,24 @@ Connection::PollData Connection::getEventLoopPollData() const
|
||||
return {pollData.fd, pollData.events, timeout, eventFd_.fd};
|
||||
}
|
||||
|
||||
void Connection::addObjectManager(const ObjectPath& objectPath)
|
||||
const ISdBus& Connection::getSdBusInterface() const
|
||||
{
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
ISdBus& Connection::getSdBusInterface()
|
||||
{
|
||||
return *sdbus_.get();
|
||||
}
|
||||
|
||||
void Connection::addObjectManager(const std::string& objectPath, floating_slot_t)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_add_object_manager(bus_.get(), nullptr, objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add object manager", -r);
|
||||
}
|
||||
|
||||
Slot Connection::addObjectManager(const ObjectPath& objectPath, return_slot_t)
|
||||
Slot Connection::addObjectManager(const std::string& objectPath, return_slot_t)
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
@@ -217,7 +203,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(static_cast<sd_bus_slot*>(slot)); }};
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
void Connection::setMethodCallTimeout(uint64_t timeout)
|
||||
@@ -229,7 +215,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);
|
||||
|
||||
@@ -238,12 +224,7 @@ uint64_t Connection::getMethodCallTimeout() const
|
||||
return timeout;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
|
||||
|
||||
@@ -253,20 +234,17 @@ 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(static_cast<sd_bus_slot*>(slot)); }};
|
||||
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
|
||||
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }};
|
||||
}
|
||||
|
||||
void Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback)
|
||||
void Connection::addMatch(const std::string& match, message_handler callback, floating_slot_t)
|
||||
{
|
||||
floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback), return_slot));
|
||||
floatingMatchRules_.push_back(addMatch(match, std::move(callback)));
|
||||
}
|
||||
|
||||
Slot Connection::addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, return_slot_t )
|
||||
Slot Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL);
|
||||
|
||||
@@ -282,9 +260,14 @@ 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(static_cast<sd_bus_slot*>(slot)); }};
|
||||
matchInfo->slot = {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
|
||||
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return {matchInfo.release(), [](void *ptr){ delete static_cast<MatchInfo*>(ptr); }};
|
||||
}
|
||||
|
||||
void Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t)
|
||||
{
|
||||
floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback)));
|
||||
}
|
||||
|
||||
void Connection::attachSdEventLoop(sd_event *event, int priority)
|
||||
@@ -329,7 +312,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(static_cast<sd_event*>(event)); }};
|
||||
return Slot{event, [](void* event){ sd_event_unref((sd_event*)event); }};
|
||||
}
|
||||
|
||||
Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority)
|
||||
@@ -337,7 +320,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(static_cast<sd_event_source*>(source)); }};
|
||||
Slot sdTimeEventSource{timeEventSource, [](void* source){ deleteSdEventSource((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);
|
||||
@@ -348,12 +331,12 @@ Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority)
|
||||
return sdTimeEventSource;
|
||||
}
|
||||
|
||||
Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority)
|
||||
{
|
||||
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(static_cast<sd_event_source*>(source)); }};
|
||||
Slot sdIoEventSource{ioEventSource, [](void* source){ deleteSdEventSource((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);
|
||||
@@ -367,12 +350,12 @@ Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority
|
||||
return sdIoEventSource;
|
||||
}
|
||||
|
||||
Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int priority) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int priority)
|
||||
{
|
||||
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(static_cast<sd_event_source*>(source)); }};
|
||||
Slot sdInternalEventSource{internalEventSource, [](void* source){ deleteSdEventSource((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.
|
||||
@@ -390,7 +373,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();
|
||||
@@ -400,7 +383,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();
|
||||
@@ -410,7 +393,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.
|
||||
@@ -433,7 +416,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();
|
||||
@@ -455,29 +438,28 @@ 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 != std::chrono::microseconds::max() ? SD_EVENT_ONESHOT : SD_EVENT_OFF);
|
||||
r = sd_event_source_set_enabled(sdTimeEventSource, sdbusPollData.timeout != sdbusPollData.timeout.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 *source)
|
||||
void Connection::deleteSdEventSource(sd_event_source *s)
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=243
|
||||
sd_event_source_disable_unref(source);
|
||||
sd_event_source_disable_unref(s);
|
||||
#else
|
||||
sd_event_source_set_enabled(source, SD_EVENT_OFF);
|
||||
sd_event_source_unref(source);
|
||||
sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||
sd_event_source_unref(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SDBUS_basu
|
||||
|
||||
Slot Connection::addObjectVTable( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData
|
||||
, return_slot_t )
|
||||
, void* userData )
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
@@ -490,7 +472,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(static_cast<sd_bus_slot*>(slot)); }};
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
PlainMessage Connection::createPlainMessage() const
|
||||
@@ -501,248 +483,164 @@ 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);
|
||||
return Message::Factory::create<PlainMessage>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
MethodCall Connection::createMethodCall( const ServiceName& destination
|
||||
, const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const MethodName& methodName ) const
|
||||
{
|
||||
return Connection::createMethodCall(destination.c_str(), objectPath.c_str(), interfaceName.c_str(), methodName.c_str());
|
||||
}
|
||||
|
||||
MethodCall Connection::createMethodCall( const char* destination
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* methodName ) const
|
||||
MethodCall Connection::createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_method_call( bus_.get()
|
||||
, &sdbusMsg
|
||||
, *destination == '\0' ? nullptr : destination
|
||||
, objectPath
|
||||
, interfaceName
|
||||
, methodName);
|
||||
, destination.empty() ? nullptr : destination.c_str()
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, methodName.c_str() );
|
||||
|
||||
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);
|
||||
return Message::Factory::create<MethodCall>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
Signal Connection::createSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const SignalName& signalName ) const
|
||||
{
|
||||
return Connection::createSignal(objectPath.c_str(), interfaceName.c_str(), signalName.c_str());
|
||||
}
|
||||
|
||||
Signal Connection::createSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName ) const
|
||||
Signal Connection::createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_signal(bus_.get(), &sdbusMsg, objectPath, interfaceName, signalName);
|
||||
auto r = sdbus_->sd_bus_message_new_signal( bus_.get()
|
||||
, &sdbusMsg
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, signalName.c_str() );
|
||||
|
||||
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);
|
||||
return Message::Factory::create<Signal>(sdbusMsg, sdbus_.get(), adopt_message);
|
||||
}
|
||||
|
||||
void Connection::emitPropertiesChangedSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const std::vector<PropertyName>& propNames )
|
||||
MethodReply Connection::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
Connection::emitPropertiesChangedSignal(objectPath.c_str(), interfaceName.c_str(), propNames);
|
||||
// If the call expects reply, this call will block the bus connection from
|
||||
// serving other messages until the reply arrives or the call times out.
|
||||
auto reply = message.send(timeout);
|
||||
|
||||
// Wake up event loop to process messages that may have arrived in the meantime...
|
||||
wakeUpEventLoopIfMessagesInQueue();
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Connection::emitPropertiesChangedSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const std::vector<PropertyName>& propNames )
|
||||
void Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
message.send(callback, userData, timeout, floating_slot);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
}
|
||||
|
||||
Slot Connection::callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout)
|
||||
{
|
||||
// TODO: Think of ways of optimizing these three locking/unlocking of sdbus mutex (merge into one call?)
|
||||
auto timeoutBefore = getEventLoopPollData().timeout;
|
||||
auto slot = message.send(callback, userData, timeout);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
if (timeoutAfter < timeoutBefore)
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames )
|
||||
{
|
||||
auto names = to_strv(propNames);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_properties_changed_strv( bus_.get()
|
||||
, objectPath
|
||||
, interfaceName
|
||||
, propNames.empty() ? nullptr : names.data() );
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, propNames.empty() ? nullptr : &names[0] );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit PropertiesChanged signal", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesAddedSignal(const ObjectPath& objectPath)
|
||||
void Connection::emitInterfacesAddedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_emit_object_added(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal for all registered interfaces", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesAddedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces )
|
||||
void Connection::emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_added_strv( bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : names.data() );
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesAdded signal", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesRemovedSignal(const ObjectPath& objectPath)
|
||||
void Connection::emitInterfacesRemovedSignal(const std::string& objectPath)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_emit_object_removed(bus_.get(), objectPath.c_str());
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal for all registered interfaces", -r);
|
||||
}
|
||||
|
||||
void Connection::emitInterfacesRemovedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces )
|
||||
void Connection::emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv( bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : names.data() );
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit InterfacesRemoved signal", -r);
|
||||
}
|
||||
|
||||
Slot Connection::registerSignalHandler( const char* sender
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName
|
||||
Slot Connection::registerSignalHandler( const std::string& sender
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, sd_bus_message_handler_t callback
|
||||
, void* userData
|
||||
, return_slot_t )
|
||||
, void* userData )
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = sdbus_->sd_bus_match_signal( bus_.get()
|
||||
, &slot
|
||||
, *sender == '\0' ? nullptr : sender
|
||||
, *objectPath == '\0' ? nullptr : objectPath
|
||||
, *interfaceName == '\0' ? nullptr : interfaceName
|
||||
, *signalName == '\0' ? nullptr : signalName
|
||||
, !sender.empty() ? sender.c_str() : nullptr
|
||||
, !objectPath.empty() ? objectPath.c_str() : nullptr
|
||||
, !interfaceName.empty() ? interfaceName.c_str() : nullptr
|
||||
, !signalName.empty() ? signalName.c_str() : nullptr
|
||||
, callback
|
||||
, userData );
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
|
||||
|
||||
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)
|
||||
{
|
||||
return sdbus_->sd_bus_message_ref(sdbusMsg);
|
||||
}
|
||||
|
||||
sd_bus_message* Connection::decrementMessageRefCount(sd_bus_message* sdbusMsg)
|
||||
{
|
||||
return sdbus_->sd_bus_message_unref(sdbusMsg);
|
||||
}
|
||||
|
||||
int Connection::querySenderCredentials(sd_bus_message* sdbusMsg, uint64_t mask, sd_bus_creds **creds)
|
||||
{
|
||||
return sdbus_->sd_bus_query_sender_creds(sdbusMsg, mask, creds);
|
||||
}
|
||||
|
||||
sd_bus_creds* Connection::incrementCredsRefCount(sd_bus_creds* creds)
|
||||
{
|
||||
return sdbus_->sd_bus_creds_ref(creds);
|
||||
}
|
||||
|
||||
sd_bus_creds* Connection::decrementCredsRefCount(sd_bus_creds* creds)
|
||||
{
|
||||
return sdbus_->sd_bus_creds_unref(creds);
|
||||
}
|
||||
|
||||
sd_bus_message* Connection::callMethod(sd_bus_message* sdbusMsg, uint64_t timeout)
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
// This call will block the bus connection from serving other messages
|
||||
// until the reply arrives or the call times out.
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_call(nullptr, sdbusMsg, timeout, &sdbusError, &sdbusReply);
|
||||
|
||||
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);
|
||||
|
||||
// Wake up event loop to process messages that may have arrived in the meantime,
|
||||
// or to dispatch the outbound message that hasn't yet been fully sent out.
|
||||
wakeUpEventLoopIfMessagesInQueue();
|
||||
|
||||
return sdbusReply;
|
||||
}
|
||||
|
||||
Slot Connection::callMethodAsync(sd_bus_message* sdbusMsg, sd_bus_message_handler_t callback, void* userData, uint64_t timeout, return_slot_t)
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
// 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, callback, userData, timeout);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
|
||||
auto timeoutAfter = getEventLoopPollData().timeout;
|
||||
|
||||
// An event loop may wait in poll with timeout `t1', while in another thread an async call is made with
|
||||
// timeout `t2'. If `t2' < `t1', then we have to wake up the event loop thread to update its poll timeout.
|
||||
// We also have to wake up the event loop to process the messages that may be in the read/write queues.
|
||||
if (timeoutAfter < timeoutBefore || arePendingMessagesInQueues())
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref(static_cast<sd_bus_slot*>(slot)); }};
|
||||
}
|
||||
|
||||
void Connection::sendMessage(sd_bus_message* sdbusMsg)
|
||||
{
|
||||
auto r = sdbus_->sd_bus_send(nullptr, sdbusMsg, nullptr);
|
||||
|
||||
// Wake up event loop to continue dispatching the (fairly large) outbound message that hasn't yet been fully sent
|
||||
wakeUpEventLoopIfMessagesInQueue();
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send D-Bus message", -r);
|
||||
}
|
||||
|
||||
sd_bus_message* Connection::createMethodReply(sd_bus_message* sdbusMsg)
|
||||
{
|
||||
sd_bus_message* sdbusReply{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_method_return(sdbusMsg, &sdbusReply);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
|
||||
|
||||
return sdbusReply;
|
||||
}
|
||||
|
||||
sd_bus_message* Connection::createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error)
|
||||
{
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
sd_bus_error_set(&sdbusError, error.getName().c_str(), error.getMessage().c_str());
|
||||
|
||||
sd_bus_message* sdbusErrorReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_error(sdbusMsg, &sdbusErrorReply, &sdbusError);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method error reply", -r);
|
||||
|
||||
return sdbusErrorReply;
|
||||
return {slot, [this](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
|
||||
{
|
||||
sd_bus* bus{};
|
||||
const int r = busFactory(&bus);
|
||||
int r = busFactory(&bus);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
|
||||
|
||||
BusPtr busPtr{bus, [this](sd_bus* bus){ return sdbus_->sd_bus_flush_close_unref(bus); }};
|
||||
@@ -754,7 +652,7 @@ Connection::BusPtr Connection::openPseudoBus()
|
||||
{
|
||||
sd_bus* bus{};
|
||||
|
||||
const int r = sdbus_->sd_bus_new(&bus);
|
||||
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);
|
||||
@@ -792,15 +690,11 @@ void Connection::notifyEventLoopToWakeUpFromPoll()
|
||||
|
||||
void Connection::wakeUpEventLoopIfMessagesInQueue()
|
||||
{
|
||||
// We need this in two cases:
|
||||
// 1. When doing a sync call, other D-Bus messages may have arrived, waiting in the read queue.
|
||||
// When doing a sync call, other D-Bus messages may have arrived, waiting in the read queue.
|
||||
// In case an event loop is inside a poll in another thread, or an external event loop polls in the
|
||||
// same thread but as an unrelated event source, then we need to wake up the poll explicitly so the
|
||||
// event loop 1. processes all messages in the read queue, 2. updates poll timeout before next poll.
|
||||
// 2. Additionally, when sending out messages, these may be too long to be sent out entirely within
|
||||
// the single sd_bus_send() or sd_bus_call_async() call, in which case they are queued in the write
|
||||
// queue. We need to wake up the event loop to continue sending the message until it's fully sent.
|
||||
if (arePendingMessagesInQueues())
|
||||
if (arePendingMessagesInReadQueue())
|
||||
notifyEventLoopToWakeUpFromPoll();
|
||||
}
|
||||
|
||||
@@ -812,10 +706,10 @@ void Connection::joinWithEventLoop()
|
||||
|
||||
bool Connection::processPendingEvent()
|
||||
{
|
||||
auto *bus = bus_.get();
|
||||
auto bus = bus_.get();
|
||||
assert(bus != nullptr);
|
||||
|
||||
const int r = sdbus_->sd_bus_process(bus, nullptr);
|
||||
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()
|
||||
@@ -827,7 +721,7 @@ bool Connection::processPendingEvent()
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
bool Connection::waitForNextEvent() // NOLINT(misc-no-recursion)
|
||||
bool Connection::waitForNextEvent()
|
||||
{
|
||||
assert(bus_ != nullptr);
|
||||
assert(loopExitFd_.fd >= 0);
|
||||
@@ -839,8 +733,6 @@ bool Connection::waitForNextEvent() // NOLINT(misc-no-recursion)
|
||||
, {loopExitFd_.fd, POLLIN, 0} };
|
||||
constexpr auto fdsCount = sizeof(fds)/sizeof(fds[0]);
|
||||
|
||||
// Are there pending messages in the inbound queue? Then sd-bus will set timeout to 0, so poll() will wake up right away.
|
||||
// Are there pending messages in the outbound queue? Then sd-bus will add POLLOUT to events, so poll() will wake up right away.
|
||||
auto timeout = sdbusPollData.getPollTimeout();
|
||||
auto r = poll(fds, fdsCount, timeout);
|
||||
|
||||
@@ -850,15 +742,15 @@ bool Connection::waitForNextEvent() // NOLINT(misc-no-recursion)
|
||||
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) // NOLINT(readability-implicit-bool-conversion)
|
||||
if (fds[1].revents & POLLIN)
|
||||
{
|
||||
auto cleared = eventFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the event descriptor", -errno);
|
||||
// Go poll() again, but with freshly calculated, up-to-date timeout and with up-to-date events to watch
|
||||
// Go poll() again, but with up-to-date timeout (which will wake poll() up right away if there are messages to process)
|
||||
return waitForNextEvent();
|
||||
}
|
||||
// Loop exit notification
|
||||
if (fds[2].revents & POLLIN) // NOLINT(readability-implicit-bool-conversion)
|
||||
if (fds[2].revents & POLLIN)
|
||||
{
|
||||
auto cleared = loopExitFd_.clear();
|
||||
SDBUS_THROW_ERROR_IF(!cleared, "Failed to read from the loop exit descriptor", -errno);
|
||||
@@ -868,33 +760,28 @@ bool Connection::waitForNextEvent() // NOLINT(misc-no-recursion)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::arePendingMessagesInQueues() const
|
||||
bool Connection::arePendingMessagesInReadQueue() const
|
||||
{
|
||||
uint64_t readQueueSize{};
|
||||
uint64_t writeQueueSize{};
|
||||
|
||||
auto r = sdbus_->sd_bus_get_n_queued(bus_.get(), &readQueueSize, &writeQueueSize);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get number of pending messages in sd-bus queues", -r);
|
||||
auto r = sdbus_->sd_bus_get_n_queued_read(bus_.get(), &readQueueSize);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get number of pending messages in read queue", -r);
|
||||
|
||||
return readQueueSize > 0 || writeQueueSize > 0;
|
||||
return readQueueSize > 0;
|
||||
}
|
||||
|
||||
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));
|
||||
return Message::Factory::create<Message>(sdbusMsg, sdbus_.get());
|
||||
}
|
||||
|
||||
template <typename StringBasedType>
|
||||
std::vector</*const */char*> Connection::to_strv(const std::vector<StringBasedType>& strings)
|
||||
std::vector</*const */char*> Connection::to_strv(const std::vector<std::string>& strings)
|
||||
{
|
||||
std::vector</*const */char*> strv;
|
||||
strv.reserve(strings.size());
|
||||
for (auto& str : strings)
|
||||
strv.push_back(const_cast<char*>(str.c_str())); // NOLINT(cppcoreguidelines-pro-type-const-cast)
|
||||
strv.push_back(const_cast<char*>(str.c_str()));
|
||||
strv.push_back(nullptr);
|
||||
return strv;
|
||||
}
|
||||
@@ -905,7 +792,7 @@ int Connection::sdbus_match_callback(sd_bus_message *sdbusMessage, void *userDat
|
||||
assert(matchInfo != nullptr);
|
||||
assert(matchInfo->callback);
|
||||
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection);
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->callback(std::move(message)); }, retError);
|
||||
|
||||
@@ -918,7 +805,7 @@ int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void
|
||||
assert(matchInfo != nullptr);
|
||||
assert(matchInfo->installCallback);
|
||||
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection);
|
||||
auto message = Message::Factory::create<PlainMessage>(sdbusMessage, &matchInfo->connection.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->installCallback(std::move(message)); }, retError);
|
||||
|
||||
@@ -926,8 +813,8 @@ int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void
|
||||
}
|
||||
|
||||
Connection::EventFd::EventFd()
|
||||
: fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
|
||||
{
|
||||
fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
SDBUS_THROW_ERROR_IF(fd < 0, "Failed to create event object", -errno);
|
||||
}
|
||||
|
||||
@@ -937,14 +824,14 @@ Connection::EventFd::~EventFd()
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void Connection::EventFd::notify() // NOLINT(readability-make-member-function-const)
|
||||
void Connection::EventFd::notify()
|
||||
{
|
||||
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() // NOLINT(readability-make-member-function-const)
|
||||
bool Connection::EventFd::clear()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
|
||||
@@ -965,10 +852,10 @@ std::chrono::microseconds IConnection::PollData::getRelativeTimeout() const
|
||||
|
||||
if (timeout == zero)
|
||||
return zero;
|
||||
if (timeout == max)
|
||||
else if (timeout == max)
|
||||
return max;
|
||||
|
||||
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
|
||||
else
|
||||
return std::max(std::chrono::duration_cast<std::chrono::microseconds>(timeout - now()), zero);
|
||||
}
|
||||
|
||||
int IConnection::PollData::getPollTimeout() const
|
||||
@@ -977,18 +864,18 @@ int IConnection::PollData::getPollTimeout() const
|
||||
|
||||
if (relativeTimeout == decltype(relativeTimeout)::max())
|
||||
return -1;
|
||||
|
||||
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
|
||||
else
|
||||
return static_cast<int>(std::chrono::ceil<std::chrono::milliseconds>(relativeTimeout).count());
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
std::unique_ptr<IConnection> createPseudoConnection()
|
||||
std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection()
|
||||
{
|
||||
auto interface = std::make_unique<SdBus>();
|
||||
return std::make_unique<Connection>(std::move(interface), Connection::pseudo_bus);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::pseudo_bus);
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
@@ -997,81 +884,81 @@ namespace sdbus {
|
||||
|
||||
using internal::Connection;
|
||||
|
||||
std::unique_ptr<IConnection> createBusConnection()
|
||||
std::unique_ptr<sdbus::IConnection> createBusConnection()
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::default_bus);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::default_bus);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createBusConnection(const ServiceName& name)
|
||||
std::unique_ptr<sdbus::IConnection> createBusConnection(const std::string& name)
|
||||
{
|
||||
auto conn = createBusConnection();
|
||||
conn->requestName(name);
|
||||
return conn;
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createSystemBusConnection()
|
||||
std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::system_bus);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::system_bus);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createSystemBusConnection(const ServiceName& name)
|
||||
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
|
||||
{
|
||||
auto conn = createSystemBusConnection();
|
||||
conn->requestName(name);
|
||||
return conn;
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createSessionBusConnection()
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::session_bus);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::session_bus);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createSessionBusConnection(const ServiceName& name)
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)
|
||||
{
|
||||
auto conn = createSessionBusConnection();
|
||||
conn->requestName(name);
|
||||
return conn;
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createSessionBusConnectionWithAddress(const std::string &address)
|
||||
std::unique_ptr<sdbus::IConnection> createSessionBusConnectionWithAddress(const std::string &address)
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::custom_session_bus, address);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::custom_session_bus, address);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createRemoteSystemBusConnection(const std::string& host)
|
||||
std::unique_ptr<sdbus::IConnection> createRemoteSystemBusConnection(const std::string& host)
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::remote_system_bus, host);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::remote_system_bus, host);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createDirectBusConnection(const std::string& address)
|
||||
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(const std::string& address)
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::private_bus, address);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, address);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createDirectBusConnection(int fd)
|
||||
std::unique_ptr<sdbus::IConnection> createDirectBusConnection(int fd)
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::private_bus, fd);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::private_bus, fd);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createServerBus(int fd)
|
||||
std::unique_ptr<sdbus::IConnection> createServerBus(int fd)
|
||||
{
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::server_bus, fd);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::server_bus, fd);
|
||||
}
|
||||
|
||||
std::unique_ptr<IConnection> createBusConnection(sd_bus *bus)
|
||||
std::unique_ptr<sdbus::IConnection> createBusConnection(sd_bus *bus)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(bus == nullptr, "Invalid bus argument", EINVAL);
|
||||
|
||||
auto interface = std::make_unique<internal::SdBus>();
|
||||
return std::make_unique<internal::Connection>(std::move(interface), Connection::sdbus_bus, bus);
|
||||
auto interface = std::make_unique<sdbus::internal::SdBus>();
|
||||
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::sdbus_bus, bus);
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
+64
-104
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection.h
|
||||
*
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "IConnection.h"
|
||||
#include "ISdBus.h"
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -40,44 +41,33 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
struct sd_event_source;
|
||||
namespace sdbus {
|
||||
class ObjectPath;
|
||||
class InterfaceName;
|
||||
class BusName;
|
||||
using ServiceName = BusName;
|
||||
class MemberName;
|
||||
using MethodName = MemberName;
|
||||
using SignalName = MemberName;
|
||||
using PropertyName = MemberName;
|
||||
} // namespace sdbus
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
class Connection final
|
||||
: public IConnection
|
||||
: public sdbus::internal::IConnection
|
||||
{
|
||||
public:
|
||||
// Bus type tags
|
||||
struct default_bus_t{};
|
||||
static constexpr default_bus_t default_bus{};
|
||||
inline static constexpr default_bus_t default_bus{};
|
||||
struct system_bus_t{};
|
||||
static constexpr system_bus_t system_bus{};
|
||||
inline static constexpr system_bus_t system_bus{};
|
||||
struct session_bus_t{};
|
||||
static constexpr session_bus_t session_bus{};
|
||||
inline static constexpr session_bus_t session_bus{};
|
||||
struct custom_session_bus_t{};
|
||||
static constexpr custom_session_bus_t custom_session_bus{};
|
||||
inline static constexpr custom_session_bus_t custom_session_bus{};
|
||||
struct remote_system_bus_t{};
|
||||
static constexpr remote_system_bus_t remote_system_bus{};
|
||||
inline static constexpr remote_system_bus_t remote_system_bus{};
|
||||
struct private_bus_t{};
|
||||
static constexpr private_bus_t private_bus{};
|
||||
inline static constexpr private_bus_t private_bus{};
|
||||
struct server_bus_t{};
|
||||
static constexpr server_bus_t server_bus{};
|
||||
inline static constexpr server_bus_t server_bus{};
|
||||
struct sdbus_bus_t{}; // A bus connection created directly from existing sd_bus instance
|
||||
static constexpr sdbus_bus_t sdbus_bus{};
|
||||
inline static constexpr sdbus_bus_t sdbus_bus{};
|
||||
struct pseudo_bus_t{}; // A bus connection that is not really established with D-Bus daemon
|
||||
static constexpr pseudo_bus_t pseudo_bus{};
|
||||
inline 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);
|
||||
@@ -89,15 +79,11 @@ 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;
|
||||
void releaseName(const ServiceName& name) override;
|
||||
[[nodiscard]] BusName getUniqueName() const override;
|
||||
void requestName(const std::string& name) override;
|
||||
void releaseName(const std::string& name) override;
|
||||
[[nodiscard]] std::string getUniqueName() const override;
|
||||
void enterEventLoop() override;
|
||||
void enterEventLoopAsync() override;
|
||||
void leaveEventLoop() override;
|
||||
@@ -105,80 +91,58 @@ namespace sdbus::internal {
|
||||
bool processPendingEvent() override;
|
||||
Message getCurrentlyProcessedMessage() const override;
|
||||
|
||||
void addObjectManager(const ObjectPath& objectPath) override;
|
||||
Slot addObjectManager(const ObjectPath& objectPath, return_slot_t) override;
|
||||
void addObjectManager(const std::string& objectPath, floating_slot_t) override;
|
||||
Slot addObjectManager(const std::string& objectPath, return_slot_t) override;
|
||||
|
||||
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;
|
||||
[[nodiscard]] Slot addMatchAsync( const std::string& match
|
||||
, message_handler callback
|
||||
, message_handler installCallback
|
||||
, return_slot_t ) override;
|
||||
[[nodiscard]] Slot addMatch(const std::string& match, message_handler callback) override;
|
||||
void addMatch(const std::string& match, message_handler callback, floating_slot_t) override;
|
||||
[[nodiscard]] Slot addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) override;
|
||||
void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) override;
|
||||
|
||||
void attachSdEventLoop(sd_event *event, int priority) override;
|
||||
void detachSdEventLoop() override;
|
||||
sd_event *getSdEventLoop() override;
|
||||
|
||||
Slot addObjectVTable( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
[[nodiscard]] const ISdBus& getSdBusInterface() const override;
|
||||
[[nodiscard]] ISdBus& getSdBusInterface() override;
|
||||
|
||||
Slot addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData
|
||||
, return_slot_t ) override;
|
||||
, void* userData ) override;
|
||||
|
||||
[[nodiscard]] PlainMessage createPlainMessage() const override;
|
||||
[[nodiscard]] MethodCall createMethodCall( const ServiceName& destination
|
||||
, const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const MethodName& methodName ) const override;
|
||||
[[nodiscard]] MethodCall createMethodCall( const char* destination
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* methodName ) const override;
|
||||
[[nodiscard]] Signal createSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const SignalName& signalName ) const override;
|
||||
[[nodiscard]] Signal createSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName ) const override;
|
||||
[[nodiscard]] MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const override;
|
||||
[[nodiscard]] Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const override;
|
||||
|
||||
void emitPropertiesChangedSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const std::vector<PropertyName>& propNames ) override;
|
||||
void emitPropertiesChangedSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const std::vector<PropertyName>& propNames ) override;
|
||||
void emitInterfacesAddedSignal(const ObjectPath& objectPath) override;
|
||||
void emitInterfacesAddedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces ) override;
|
||||
void emitInterfacesRemovedSignal(const ObjectPath& objectPath) override;
|
||||
void emitInterfacesRemovedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces ) override;
|
||||
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
||||
void callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t) override;
|
||||
Slot callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout) override;
|
||||
|
||||
Slot registerSignalHandler( const char* sender
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName
|
||||
void emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames ) override;
|
||||
void emitInterfacesAddedSignal(const std::string& objectPath) override;
|
||||
void emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) override;
|
||||
void emitInterfacesRemovedSignal(const std::string& objectPath) override;
|
||||
void emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) override;
|
||||
|
||||
Slot registerSignalHandler( const std::string& sender
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, sd_bus_message_handler_t callback
|
||||
, void* userData
|
||||
, return_slot_t ) override;
|
||||
|
||||
sd_bus_message* incrementMessageRefCount(sd_bus_message* sdbusMsg) override;
|
||||
sd_bus_message* decrementMessageRefCount(sd_bus_message* sdbusMsg) override;
|
||||
|
||||
int querySenderCredentials(sd_bus_message* sdbusMsg, uint64_t mask, sd_bus_creds **creds) override;
|
||||
sd_bus_creds* incrementCredsRefCount(sd_bus_creds* creds) override;
|
||||
sd_bus_creds* decrementCredsRefCount(sd_bus_creds* creds) override;
|
||||
|
||||
sd_bus_message* callMethod(sd_bus_message* sdbusMsg, uint64_t timeout) override;
|
||||
Slot callMethodAsync(sd_bus_message* sdbusMsg, sd_bus_message_handler_t callback, void* userData, uint64_t timeout, return_slot_t) override;
|
||||
void sendMessage(sd_bus_message* sdbusMsg) override;
|
||||
|
||||
sd_bus_message* createMethodReply(sd_bus_message* sdbusMsg) override;
|
||||
sd_bus_message* createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error) override;
|
||||
, void* userData ) override;
|
||||
|
||||
private:
|
||||
using BusFactory = std::function<int(sd_bus**)>;
|
||||
@@ -190,40 +154,35 @@ namespace sdbus::internal {
|
||||
void finishHandshake(sd_bus* bus);
|
||||
bool waitForNextEvent();
|
||||
|
||||
[[nodiscard]] bool arePendingMessagesInQueues() const;
|
||||
[[nodiscard]] bool arePendingMessagesInReadQueue() const;
|
||||
|
||||
void notifyEventLoopToExit();
|
||||
void notifyEventLoopToWakeUpFromPoll();
|
||||
void wakeUpEventLoopIfMessagesInQueue();
|
||||
void joinWithEventLoop();
|
||||
|
||||
template <typename StringBasedType>
|
||||
static std::vector</*const */char*> to_strv(const std::vector<StringBasedType>& strings);
|
||||
static std::vector</*const */char*> to_strv(const std::vector<std::string>& strings);
|
||||
|
||||
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
|
||||
static Slot createSdEventSlot(sd_event *event);
|
||||
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 *source);
|
||||
static void deleteSdEventSource(sd_event_source *s);
|
||||
|
||||
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);
|
||||
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);
|
||||
#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();
|
||||
@@ -235,7 +194,7 @@ namespace sdbus::internal {
|
||||
{
|
||||
message_handler callback;
|
||||
message_handler installCallback;
|
||||
Connection& connection; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
Connection& connection;
|
||||
Slot slot;
|
||||
};
|
||||
|
||||
@@ -248,6 +207,7 @@ namespace sdbus::internal {
|
||||
Slot sdInternalEventSource;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<ISdBus> sdbus_;
|
||||
BusPtr bus_;
|
||||
std::thread asyncLoopThread_;
|
||||
@@ -257,6 +217,6 @@ namespace sdbus::internal {
|
||||
std::unique_ptr<SdEvent> sdEvent_; // Integration of systemd sd-event event loop implementation
|
||||
};
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_CONNECTION_H_ */
|
||||
|
||||
+5
-18
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Error.cpp
|
||||
*
|
||||
@@ -29,30 +29,17 @@
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
#include SDBUS_HEADER
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
Error createError(int errNo, std::string customMsg)
|
||||
sdbus::Error createError(int errNo, const 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(sd_bus_error_is_set(&sdbusError) != 0 ? sdbusError.name : "");
|
||||
std::string message(std::move(customMsg));
|
||||
if (!message.empty() && sdbusError.message != nullptr)
|
||||
{
|
||||
message.append(" (");
|
||||
message.append(sdbusError.message);
|
||||
message.append(")");
|
||||
}
|
||||
else if (sdbusError.message != nullptr)
|
||||
{
|
||||
message = sdbusError.message;
|
||||
}
|
||||
|
||||
return {std::move(name), std::move(message)};
|
||||
std::string name(sdbusError.name);
|
||||
std::string message(customMsg + " (" + sdbusError.message + ")");
|
||||
return sdbus::Error(name, message);
|
||||
}
|
||||
} // namespace sdbus
|
||||
|
||||
+7
-3
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Flags.cpp
|
||||
*
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include SDBUS_HEADER
|
||||
#include <cstdint>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
@@ -34,6 +33,7 @@ namespace sdbus
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
@@ -55,6 +55,7 @@ namespace sdbus
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
@@ -69,6 +70,7 @@ namespace sdbus
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
|
||||
@@ -79,6 +81,7 @@ namespace sdbus
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
//if (!flags_.test(Flags::PRIVILEGED))
|
||||
@@ -100,9 +103,10 @@ namespace sdbus
|
||||
{
|
||||
auto sdbusFlags = toSdBusPropertyFlags();
|
||||
|
||||
using namespace sdbus;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
+42
-70
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file IConnection.h
|
||||
*
|
||||
@@ -31,29 +31,22 @@
|
||||
|
||||
#include "sdbus-c++/TypeTraits.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include SDBUS_HEADER
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
// Forward declaration
|
||||
namespace sdbus {
|
||||
class MethodCall;
|
||||
class MethodReply;
|
||||
class Signal;
|
||||
class PlainMessage;
|
||||
class ObjectPath;
|
||||
class InterfaceName;
|
||||
class BusName;
|
||||
using ServiceName = BusName;
|
||||
class MemberName;
|
||||
using MethodName = MemberName;
|
||||
using SignalName = MemberName;
|
||||
using PropertyName = MemberName;
|
||||
class Error;
|
||||
namespace internal {
|
||||
class ISdBus;
|
||||
} // namespace internal
|
||||
} // namespace sdbus
|
||||
}
|
||||
}
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
@@ -63,71 +56,50 @@ namespace sdbus::internal {
|
||||
public:
|
||||
~IConnection() override = default;
|
||||
|
||||
[[nodiscard]] virtual Slot addObjectVTable( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
[[nodiscard]] virtual const ISdBus& getSdBusInterface() const = 0;
|
||||
[[nodiscard]] virtual ISdBus& getSdBusInterface() = 0;
|
||||
|
||||
[[nodiscard]] virtual Slot addObjectVTable( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const sd_bus_vtable* vtable
|
||||
, void* userData
|
||||
, return_slot_t ) = 0;
|
||||
, void* userData ) = 0;
|
||||
|
||||
[[nodiscard]] virtual PlainMessage createPlainMessage() const = 0;
|
||||
[[nodiscard]] virtual MethodCall createMethodCall( const ServiceName& destination
|
||||
, const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const MethodName& methodName ) const = 0;
|
||||
[[nodiscard]] virtual MethodCall createMethodCall( const char* destination
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* methodName ) const = 0;
|
||||
[[nodiscard]] virtual Signal createSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const SignalName& signalName ) const = 0;
|
||||
[[nodiscard]] virtual Signal createSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName ) const = 0;
|
||||
[[nodiscard]] virtual MethodCall createMethodCall( const std::string& destination
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& methodName ) const = 0;
|
||||
[[nodiscard]] virtual Signal createSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName ) const = 0;
|
||||
|
||||
virtual void emitPropertiesChangedSignal( const ObjectPath& objectPath
|
||||
, const InterfaceName& interfaceName
|
||||
, const std::vector<PropertyName>& propNames ) = 0;
|
||||
virtual void emitPropertiesChangedSignal( const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const std::vector<PropertyName>& propNames ) = 0;
|
||||
virtual void emitInterfacesAddedSignal(const ObjectPath& objectPath) = 0;
|
||||
virtual void emitInterfacesAddedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces ) = 0;
|
||||
virtual void emitInterfacesRemovedSignal(const ObjectPath& objectPath) = 0;
|
||||
virtual void emitInterfacesRemovedSignal( const ObjectPath& objectPath
|
||||
, const std::vector<InterfaceName>& interfaces ) = 0;
|
||||
virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout) = 0;
|
||||
virtual void callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout, floating_slot_t) = 0;
|
||||
[[nodiscard]] virtual Slot callMethod(const MethodCall& message, void* callback, void* userData, uint64_t timeout) = 0;
|
||||
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const char* sender
|
||||
, const char* objectPath
|
||||
, const char* interfaceName
|
||||
, const char* signalName
|
||||
virtual void emitPropertiesChangedSignal( const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::vector<std::string>& propNames ) = 0;
|
||||
virtual void emitInterfacesAddedSignal(const std::string& objectPath) = 0;
|
||||
virtual void emitInterfacesAddedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) = 0;
|
||||
virtual void emitInterfacesRemovedSignal(const std::string& objectPath) = 0;
|
||||
virtual void emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
, const std::vector<std::string>& interfaces ) = 0;
|
||||
|
||||
using sdbus::IConnection::addObjectManager;
|
||||
[[nodiscard]] virtual Slot addObjectManager(const std::string& objectPath, return_slot_t) = 0;
|
||||
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const std::string& sender
|
||||
, const std::string& objectPath
|
||||
, const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, sd_bus_message_handler_t callback
|
||||
, void* userData
|
||||
, return_slot_t ) = 0;
|
||||
|
||||
virtual sd_bus_message* incrementMessageRefCount(sd_bus_message* sdbusMsg) = 0;
|
||||
virtual sd_bus_message* decrementMessageRefCount(sd_bus_message* sdbusMsg) = 0;
|
||||
|
||||
// TODO: Refactor to higher level (Creds class will ownership handling and getters)
|
||||
virtual int querySenderCredentials(sd_bus_message* sdbusMsg, uint64_t mask, sd_bus_creds **creds) = 0;
|
||||
virtual sd_bus_creds* incrementCredsRefCount(sd_bus_creds* creds) = 0;
|
||||
virtual sd_bus_creds* decrementCredsRefCount(sd_bus_creds* creds) = 0;
|
||||
|
||||
virtual sd_bus_message* callMethod(sd_bus_message* sdbusMsg, uint64_t timeout) = 0;
|
||||
[[nodiscard]] virtual Slot callMethodAsync( sd_bus_message* sdbusMsg
|
||||
, sd_bus_message_handler_t callback
|
||||
, void* userData
|
||||
, uint64_t timeout
|
||||
, return_slot_t ) = 0;
|
||||
virtual void sendMessage(sd_bus_message* sdbusMsg) = 0;
|
||||
|
||||
virtual sd_bus_message* createMethodReply(sd_bus_message* sdbusMsg) = 0;
|
||||
virtual sd_bus_message* createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error) = 0;
|
||||
, void* userData ) = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<IConnection> createPseudoConnection();
|
||||
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection();
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_ICONNECTION_H_ */
|
||||
|
||||
+24
-25
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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 *msg) = 0;
|
||||
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *msg) = 0;
|
||||
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 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_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_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_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_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,29 +87,28 @@ 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 **ret) = 0;
|
||||
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 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;
|
||||
virtual int sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret) = 0;
|
||||
virtual int sd_bus_flush(sd_bus *bus) = 0;
|
||||
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 *msg, const char *destination) = 0;
|
||||
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) = 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_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) = 0;
|
||||
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) = 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;
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif //SDBUS_CXX_ISDBUS_H
|
||||
|
||||
+193
-235
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message.cpp
|
||||
*
|
||||
@@ -28,50 +28,38 @@
|
||||
|
||||
#include "sdbus-c++/Error.h"
|
||||
#include "sdbus-c++/Types.h"
|
||||
#include "sdbus-c++/TypeTraits.h"
|
||||
|
||||
#include "IConnection.h"
|
||||
#include "ISdBus.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 {
|
||||
|
||||
Message::Message(internal::IConnection* connection) noexcept
|
||||
: connection_(connection)
|
||||
Message::Message(internal::ISdBus* sdbus) noexcept
|
||||
: sdbus_(sdbus)
|
||||
{
|
||||
assert(connection_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::IConnection* connection) noexcept
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus) noexcept
|
||||
: msg_(msg)
|
||||
, connection_(connection)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
assert(connection_ != nullptr);
|
||||
connection_->incrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
|
||||
assert(sdbus_ != nullptr);
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message::Message(void *msg, internal::IConnection* connection, adopt_message_t) noexcept
|
||||
Message::Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept
|
||||
: msg_(msg)
|
||||
, connection_(connection)
|
||||
, sdbus_(sdbus)
|
||||
{
|
||||
assert(msg_ != nullptr);
|
||||
assert(connection_ != nullptr);
|
||||
assert(sdbus_ != nullptr);
|
||||
}
|
||||
|
||||
Message::Message(const Message& other) noexcept
|
||||
@@ -81,17 +69,14 @@ Message::Message(const Message& other) noexcept
|
||||
|
||||
Message& Message::operator=(const Message& other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
if (msg_)
|
||||
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
connection_ = other.connection_;
|
||||
sdbus_ = other.sdbus_;
|
||||
ok_ = other.ok_;
|
||||
|
||||
connection_->incrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
|
||||
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -104,12 +89,12 @@ Message::Message(Message&& other) noexcept
|
||||
Message& Message::operator=(Message&& other) noexcept
|
||||
{
|
||||
if (msg_)
|
||||
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
|
||||
msg_ = other.msg_;
|
||||
other.msg_ = nullptr;
|
||||
connection_ = other.connection_;
|
||||
other.connection_ = nullptr;
|
||||
sdbus_ = other.sdbus_;
|
||||
other.sdbus_ = nullptr;
|
||||
ok_ = other.ok_;
|
||||
other.ok_ = true;
|
||||
|
||||
@@ -119,18 +104,14 @@ Message& Message::operator=(Message&& other) noexcept
|
||||
Message::~Message()
|
||||
{
|
||||
if (msg_)
|
||||
connection_->decrementMessageRefCount(static_cast<sd_bus_message*>(msg_));
|
||||
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
Message& Message::operator<<(bool item)
|
||||
{
|
||||
int itemAsInt = static_cast<int>(item);
|
||||
int intItem = 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(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BOOLEAN, &itemAsInt);
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a bool value", -r);
|
||||
|
||||
return *this;
|
||||
@@ -138,7 +119,7 @@ Message& Message::operator<<(bool item)
|
||||
|
||||
Message& Message::operator<<(int16_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT16, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -146,7 +127,7 @@ Message& Message::operator<<(int16_t item)
|
||||
|
||||
Message& Message::operator<<(int32_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT32, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -154,7 +135,7 @@ Message& Message::operator<<(int32_t item)
|
||||
|
||||
Message& Message::operator<<(int64_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT64, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -162,7 +143,7 @@ Message& Message::operator<<(int64_t item)
|
||||
|
||||
Message& Message::operator<<(uint8_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BYTE, &item);
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a byte value", -r);
|
||||
|
||||
return *this;
|
||||
@@ -170,7 +151,7 @@ Message& Message::operator<<(uint8_t item)
|
||||
|
||||
Message& Message::operator<<(uint16_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT16, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -178,7 +159,7 @@ Message& Message::operator<<(uint16_t item)
|
||||
|
||||
Message& Message::operator<<(uint32_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT32, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -186,7 +167,7 @@ Message& Message::operator<<(uint32_t item)
|
||||
|
||||
Message& Message::operator<<(uint64_t item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT64, &item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -194,7 +175,7 @@ Message& Message::operator<<(uint64_t item)
|
||||
|
||||
Message& Message::operator<<(double item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DOUBLE, &item);
|
||||
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a double value", -r);
|
||||
|
||||
return *this;
|
||||
@@ -202,7 +183,7 @@ Message& Message::operator<<(double item)
|
||||
|
||||
Message& Message::operator<<(const char* item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, item);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -210,23 +191,12 @@ Message& Message::operator<<(const char* item)
|
||||
|
||||
Message& Message::operator<<(const std::string& item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, item.c_str());
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(std::string_view item)
|
||||
{
|
||||
char* 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());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::operator<<(const Variant &item)
|
||||
{
|
||||
item.serializeTo(*this);
|
||||
@@ -236,7 +206,7 @@ Message& Message::operator<<(const Variant &item)
|
||||
|
||||
Message& Message::operator<<(const ObjectPath &item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_OBJECT_PATH, item.c_str());
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -244,7 +214,7 @@ Message& Message::operator<<(const ObjectPath &item)
|
||||
|
||||
Message& Message::operator<<(const Signature &item)
|
||||
{
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_SIGNATURE, item.c_str());
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -253,7 +223,7 @@ Message& Message::operator<<(const Signature &item)
|
||||
Message& Message::operator<<(const UnixFd &item)
|
||||
{
|
||||
auto fd = item.get();
|
||||
auto r = sd_bus_message_append_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
auto r = sd_bus_message_append_basic((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;
|
||||
@@ -261,7 +231,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(static_cast<sd_bus_message*>(msg_), type, ptr, size);
|
||||
auto r = sd_bus_message_append_array((sd_bus_message*)msg_, type, ptr, size);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an array", -r);
|
||||
|
||||
return *this;
|
||||
@@ -269,8 +239,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(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BOOLEAN, &intItem);
|
||||
int intItem;
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -283,7 +253,7 @@ Message& Message::operator>>(bool& item)
|
||||
|
||||
Message& Message::operator>>(int16_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT16, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -294,7 +264,7 @@ Message& Message::operator>>(int16_t& item)
|
||||
|
||||
Message& Message::operator>>(int32_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT32, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -305,7 +275,7 @@ Message& Message::operator>>(int32_t& item)
|
||||
|
||||
Message& Message::operator>>(int64_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_INT64, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -316,7 +286,7 @@ Message& Message::operator>>(int64_t& item)
|
||||
|
||||
Message& Message::operator>>(uint8_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_BYTE, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -327,7 +297,7 @@ Message& Message::operator>>(uint8_t& item)
|
||||
|
||||
Message& Message::operator>>(uint16_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT16, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -338,7 +308,7 @@ Message& Message::operator>>(uint16_t& item)
|
||||
|
||||
Message& Message::operator>>(uint32_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT32, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -349,7 +319,7 @@ Message& Message::operator>>(uint32_t& item)
|
||||
|
||||
Message& Message::operator>>(uint64_t& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UINT64, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -360,7 +330,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(static_cast<sd_bus_message*>(msg_), type, ptr, size);
|
||||
auto r = sd_bus_message_read_array((sd_bus_message*)msg_, type, ptr, size);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -371,7 +341,7 @@ Message& Message::readArray(char type, const void **ptr, size_t *size)
|
||||
|
||||
Message& Message::operator>>(double& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DOUBLE, &item);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -382,7 +352,7 @@ Message& Message::operator>>(double& item)
|
||||
|
||||
Message& Message::operator>>(char*& item)
|
||||
{
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRING, reinterpret_cast<void*>(&item));
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, &item);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -418,7 +388,7 @@ Message& Message::operator>>(Variant &item)
|
||||
Message& Message::operator>>(ObjectPath &item)
|
||||
{
|
||||
char* str{};
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_OBJECT_PATH, reinterpret_cast<void*>(&str));
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, &str);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -433,7 +403,7 @@ Message& Message::operator>>(ObjectPath &item)
|
||||
Message& Message::operator>>(Signature &item)
|
||||
{
|
||||
char* str{};
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_SIGNATURE, reinterpret_cast<void*>(&str));
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, &str);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -448,7 +418,7 @@ Message& Message::operator>>(Signature &item)
|
||||
Message& Message::operator>>(UnixFd &item)
|
||||
{
|
||||
int fd = -1;
|
||||
auto r = sd_bus_message_read_basic(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -459,9 +429,10 @@ Message& Message::operator>>(UnixFd &item)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openContainer(const char* signature)
|
||||
|
||||
Message& Message::openContainer(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_ARRAY, signature);
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a container", -r);
|
||||
|
||||
return *this;
|
||||
@@ -469,15 +440,15 @@ Message& Message::openContainer(const char* signature)
|
||||
|
||||
Message& Message::closeContainer()
|
||||
{
|
||||
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openDictEntry(const char* signature)
|
||||
Message& Message::openDictEntry(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DICT_ENTRY, signature);
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
@@ -485,15 +456,15 @@ Message& Message::openDictEntry(const char* signature)
|
||||
|
||||
Message& Message::closeDictEntry()
|
||||
{
|
||||
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openVariant(const char* signature)
|
||||
Message& Message::openVariant(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_VARIANT, signature);
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a variant", -r);
|
||||
|
||||
return *this;
|
||||
@@ -501,15 +472,15 @@ Message& Message::openVariant(const char* signature)
|
||||
|
||||
Message& Message::closeVariant()
|
||||
{
|
||||
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::openStruct(const char* signature)
|
||||
Message& Message::openStruct(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_open_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRUCT, signature);
|
||||
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a struct", -r);
|
||||
|
||||
return *this;
|
||||
@@ -517,15 +488,16 @@ Message& Message::openStruct(const char* signature)
|
||||
|
||||
Message& Message::closeStruct()
|
||||
{
|
||||
auto r = sd_bus_message_close_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a struct", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterContainer(const char* signature)
|
||||
|
||||
Message& Message::enterContainer(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_ARRAY, signature);
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -536,15 +508,15 @@ Message& Message::enterContainer(const char* signature)
|
||||
|
||||
Message& Message::exitContainer()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a container", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterDictEntry(const char* signature)
|
||||
Message& Message::enterDictEntry(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_DICT_ENTRY, signature);
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -555,15 +527,15 @@ Message& Message::enterDictEntry(const char* signature)
|
||||
|
||||
Message& Message::exitDictEntry()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a dictionary entry", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterVariant(const char* signature)
|
||||
Message& Message::enterVariant(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_VARIANT, signature);
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -574,15 +546,15 @@ Message& Message::enterVariant(const char* signature)
|
||||
|
||||
Message& Message::exitVariant()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a variant", -r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& Message::enterStruct(const char* signature)
|
||||
Message& Message::enterStruct(const std::string& signature)
|
||||
{
|
||||
auto r = sd_bus_message_enter_container(static_cast<sd_bus_message*>(msg_), SD_BUS_TYPE_STRUCT, signature);
|
||||
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
|
||||
if (r == 0)
|
||||
ok_ = false;
|
||||
|
||||
@@ -593,7 +565,7 @@ Message& Message::enterStruct(const char* signature)
|
||||
|
||||
Message& Message::exitStruct()
|
||||
{
|
||||
auto r = sd_bus_message_exit_container(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a struct", -r);
|
||||
|
||||
return *this;
|
||||
@@ -612,7 +584,7 @@ void Message::clearFlags()
|
||||
|
||||
void Message::copyTo(Message& destination, bool complete) const
|
||||
{
|
||||
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)
|
||||
auto r = sd_bus_message_copy((sd_bus_message*)destination.msg_, (sd_bus_message*)msg_, complete);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to copy the message", -r);
|
||||
}
|
||||
|
||||
@@ -620,186 +592,158 @@ void Message::seal()
|
||||
{
|
||||
const auto messageCookie = 1;
|
||||
const auto sealTimeout = 0;
|
||||
auto r = sd_bus_message_seal(static_cast<sd_bus_message*>(msg_), messageCookie, sealTimeout);
|
||||
auto r = sd_bus_message_seal((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(static_cast<sd_bus_message*>(msg_), complete); // NOLINT(readability-implicit-bool-conversion)
|
||||
auto r = sd_bus_message_rewind((sd_bus_message*)msg_, complete);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
|
||||
}
|
||||
|
||||
std::string Message::dumpToString(DumpFlags flags) const
|
||||
std::string Message::getInterfaceName() 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
|
||||
auto interface = sd_bus_message_get_interface((sd_bus_message*)msg_);
|
||||
return interface != nullptr ? interface : "";
|
||||
}
|
||||
|
||||
const char* Message::getInterfaceName() const
|
||||
std::string Message::getMemberName() const
|
||||
{
|
||||
return sd_bus_message_get_interface(static_cast<sd_bus_message*>(msg_));
|
||||
auto member = sd_bus_message_get_member((sd_bus_message*)msg_);
|
||||
return member != nullptr ? member : "";
|
||||
}
|
||||
|
||||
const char* Message::getMemberName() const
|
||||
std::string Message::getSender() const
|
||||
{
|
||||
return sd_bus_message_get_member(static_cast<sd_bus_message*>(msg_));
|
||||
return sd_bus_message_get_sender((sd_bus_message*)msg_);
|
||||
}
|
||||
|
||||
const char* Message::getSender() const
|
||||
std::string Message::getPath() const
|
||||
{
|
||||
return sd_bus_message_get_sender(static_cast<sd_bus_message*>(msg_));
|
||||
auto path = sd_bus_message_get_path((sd_bus_message*)msg_);
|
||||
return path != nullptr ? path : "";
|
||||
}
|
||||
|
||||
const char* Message::getPath() const
|
||||
std::string Message::getDestination() const
|
||||
{
|
||||
return sd_bus_message_get_path(static_cast<sd_bus_message*>(msg_));
|
||||
auto destination = sd_bus_message_get_destination((sd_bus_message*)msg_);
|
||||
return destination != nullptr ? destination : "";
|
||||
}
|
||||
|
||||
const char* Message::getDestination() const
|
||||
void Message::peekType(std::string& type, std::string& contents) const
|
||||
{
|
||||
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(static_cast<sd_bus_message*>(msg_), &cookie);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get cookie", -r);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
std::pair<char, const char*> Message::peekType() const
|
||||
{
|
||||
char typeSignature{};
|
||||
const char* contentsSignature{};
|
||||
auto r = sd_bus_message_peek_type(static_cast<sd_bus_message*>(msg_), &typeSignature, &contentsSignature);
|
||||
char typeSig;
|
||||
const char* contentsSig;
|
||||
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSig, &contentsSig);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
|
||||
return {typeSignature, contentsSignature};
|
||||
type = typeSig;
|
||||
contents = contentsSig ? contentsSig : "";
|
||||
}
|
||||
|
||||
bool Message::isValid() const
|
||||
{
|
||||
return msg_ != nullptr && connection_ != nullptr;
|
||||
return msg_ != nullptr && sdbus_ != nullptr;
|
||||
}
|
||||
|
||||
bool Message::isEmpty() const
|
||||
{
|
||||
return sd_bus_message_is_empty(static_cast<sd_bus_message*>(msg_)) != 0;
|
||||
return sd_bus_message_is_empty((sd_bus_message*)msg_) != 0;
|
||||
}
|
||||
|
||||
bool Message::isAtEnd(bool complete) const
|
||||
{
|
||||
return sd_bus_message_at_end(static_cast<sd_bus_message*>(msg_), complete) > 0; // NOLINT(readability-implicit-bool-conversion)
|
||||
return sd_bus_message_at_end((sd_bus_message*)msg_, complete) > 0;
|
||||
}
|
||||
|
||||
// TODO: Create a RAII ownership class for creds with copy&move semantics, doing ref()/unref() under the hood.
|
||||
// Create a method Message::querySenderCreds() that will return an object of this class by value, through IConnection and SdBus mutex.
|
||||
// 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
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_PID | SD_BUS_CREDS_AUGMENT;
|
||||
uint64_t mask = SD_BUS_CREDS_PID | SD_BUS_CREDS_AUGMENT;
|
||||
sd_bus_creds *creds = nullptr;
|
||||
SCOPE_EXIT{ connection_->decrementCredsRefCount(creds); };
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
|
||||
int r = connection_->querySenderCredentials(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
pid_t pid = 0;
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
r = sdbus_->sd_bus_creds_get_pid(creds, &pid);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred pid", -r);
|
||||
return pid;
|
||||
}
|
||||
|
||||
uid_t Message::getCredsUid() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_UID | SD_BUS_CREDS_AUGMENT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
auto uid = static_cast<uid_t>(-1);
|
||||
r = sd_bus_creds_get_uid(creds, &uid);
|
||||
uid_t uid = (uid_t)-1;
|
||||
r = sdbus_->sd_bus_creds_get_uid(creds, &uid);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred uid", -r);
|
||||
return uid;
|
||||
}
|
||||
|
||||
uid_t Message::getCredsEuid() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_EUID | SD_BUS_CREDS_AUGMENT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
auto euid = static_cast<uid_t>(-1);
|
||||
r = sd_bus_creds_get_euid(creds, &euid);
|
||||
uid_t euid = (uid_t)-1;
|
||||
r = sdbus_->sd_bus_creds_get_euid(creds, &euid);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred euid", -r);
|
||||
return euid;
|
||||
}
|
||||
|
||||
gid_t Message::getCredsGid() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_GID | SD_BUS_CREDS_AUGMENT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
auto gid = static_cast<gid_t>(-1);
|
||||
r = sd_bus_creds_get_gid(creds, &gid);
|
||||
gid_t gid = (gid_t)-1;
|
||||
r = sdbus_->sd_bus_creds_get_gid(creds, &gid);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred gid", -r);
|
||||
return gid;
|
||||
}
|
||||
|
||||
gid_t Message::getCredsEgid() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_EGID | SD_BUS_CREDS_AUGMENT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
auto egid = static_cast<gid_t>(-1);
|
||||
r = sd_bus_creds_get_egid(creds, &egid);
|
||||
gid_t egid = (gid_t)-1;
|
||||
r = sdbus_->sd_bus_creds_get_egid(creds, &egid);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred egid", -r);
|
||||
return egid;
|
||||
}
|
||||
|
||||
std::vector<gid_t> Message::getCredsSupplementaryGids() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_AUGMENT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
const gid_t *cGids = nullptr;
|
||||
r = sd_bus_creds_get_supplementary_gids(creds, &cGids);
|
||||
r = sdbus_->sd_bus_creds_get_supplementary_gids(creds, &cGids);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred supplementary gids", -r);
|
||||
|
||||
std::vector<gid_t> gids{};
|
||||
if (cGids != nullptr)
|
||||
{
|
||||
for (int i = 0; i < r; i++)
|
||||
gids.push_back(cGids[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
gids.push_back(cGids[i]);
|
||||
}
|
||||
|
||||
return gids;
|
||||
@@ -807,35 +751,35 @@ std::vector<gid_t> Message::getCredsSupplementaryGids() const
|
||||
|
||||
std::string Message::getSELinuxContext() const
|
||||
{
|
||||
const uint64_t mask = SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_SELINUX_CONTEXT;
|
||||
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(static_cast<sd_bus_message*>(msg_), mask, &creds);
|
||||
SCOPE_EXIT{ sdbus_->sd_bus_creds_unref(creds); };
|
||||
int r = sdbus_->sd_bus_query_sender_creds((sd_bus_message*)msg_, mask, &creds);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus creds", -r);
|
||||
|
||||
const char *cLabel = nullptr;
|
||||
r = sd_bus_creds_get_selinux_context(creds, &cLabel);
|
||||
r = sdbus_->sd_bus_creds_get_selinux_context(creds, &cLabel);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus cred selinux context", -r);
|
||||
return cLabel;
|
||||
}
|
||||
|
||||
|
||||
MethodCall::MethodCall( void *msg
|
||||
, internal::IConnection *connection
|
||||
, internal::ISdBus *sdbus
|
||||
, adopt_message_t) noexcept
|
||||
: Message(msg, connection, adopt_message)
|
||||
: Message(msg, sdbus, adopt_message)
|
||||
{
|
||||
}
|
||||
|
||||
void MethodCall::dontExpectReply()
|
||||
{
|
||||
auto r = sd_bus_message_set_expect_reply(static_cast<sd_bus_message*>(msg_), 0);
|
||||
auto r = sd_bus_message_set_expect_reply((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(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)msg_);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
|
||||
return r == 0;
|
||||
}
|
||||
@@ -844,69 +788,87 @@ MethodReply MethodCall::send(uint64_t timeout) const
|
||||
{
|
||||
if (!doesntExpectReply())
|
||||
return sendWithReply(timeout);
|
||||
|
||||
return sendWithNoReply();
|
||||
else
|
||||
return sendWithNoReply();
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithReply(uint64_t timeout) const
|
||||
{
|
||||
auto* sdbusReply = connection_->callMethod(static_cast<sd_bus_message*>(msg_), timeout);
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
|
||||
return Factory::create<MethodReply>(sdbusReply, connection_, adopt_message);
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_call(nullptr, (sd_bus_message*)msg_, timeout, &sdbusError, &sdbusReply);
|
||||
|
||||
if (sd_bus_error_is_set(&sdbusError))
|
||||
throw sdbus::Error(sdbusError.name, sdbusError.message);
|
||||
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithNoReply() const
|
||||
{
|
||||
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(); // No reply
|
||||
}
|
||||
|
||||
Slot MethodCall::send(void* callback, void* userData, uint64_t timeout, return_slot_t) const // NOLINT(bugprone-easily-swappable-parameters)
|
||||
void MethodCall::send(void* callback, void* userData, uint64_t timeout, floating_slot_t) const
|
||||
{
|
||||
return connection_->callMethodAsync(static_cast<sd_bus_message*>(msg_), reinterpret_cast<sd_bus_message_handler_t>(callback), userData, timeout, return_slot);
|
||||
auto r = sdbus_->sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, timeout);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
|
||||
}
|
||||
|
||||
Slot MethodCall::send(void* callback, void* userData, uint64_t timeout) const
|
||||
{
|
||||
sd_bus_slot* slot;
|
||||
|
||||
auto r = sdbus_->sd_bus_call_async(nullptr, &slot, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, timeout);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
|
||||
|
||||
return {slot, [sdbus_ = sdbus_](void *slot){ sdbus_->sd_bus_slot_unref((sd_bus_slot*)slot); }};
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createReply() const
|
||||
{
|
||||
auto* sdbusReply = connection_->createMethodReply(static_cast<sd_bus_message*>(msg_));
|
||||
sd_bus_message* sdbusReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_return((sd_bus_message*)msg_, &sdbusReply);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusReply, connection_, adopt_message);
|
||||
return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createErrorReply(const Error& error) const
|
||||
{
|
||||
sd_bus_message* sdbusErrorReply = connection_->createErrorReplyMessage(static_cast<sd_bus_message*>(msg_), error);
|
||||
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
|
||||
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
|
||||
sd_bus_error_set(&sdbusError, error.getName().c_str(), error.getMessage().c_str());
|
||||
|
||||
return Factory::create<MethodReply>(sdbusErrorReply, connection_, adopt_message);
|
||||
sd_bus_message* sdbusErrorReply{};
|
||||
auto r = sdbus_->sd_bus_message_new_method_error((sd_bus_message*)msg_, &sdbusErrorReply, &sdbusError);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method error reply", -r);
|
||||
|
||||
return Factory::create<MethodReply>(sdbusErrorReply, sdbus_, adopt_message);
|
||||
}
|
||||
|
||||
void MethodReply::send() const
|
||||
{
|
||||
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
|
||||
}
|
||||
|
||||
uint64_t MethodReply::getReplyCookie() const
|
||||
{
|
||||
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;
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send reply", -r);
|
||||
}
|
||||
|
||||
void Signal::send() const
|
||||
{
|
||||
connection_->sendMessage(static_cast<sd_bus_message*>(msg_));
|
||||
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
|
||||
}
|
||||
|
||||
void Signal::setDestination(const std::string& destination)
|
||||
{
|
||||
setDestination(destination.c_str());
|
||||
}
|
||||
|
||||
void Signal::setDestination(const char* destination)
|
||||
{
|
||||
auto r = sd_bus_message_set_destination(static_cast<sd_bus_message*>(msg_), destination);
|
||||
auto r = sdbus_->sd_bus_message_set_destination((sd_bus_message*)msg_, destination.c_str());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
|
||||
}
|
||||
|
||||
@@ -922,31 +884,27 @@ namespace {
|
||||
// Please note that the solution is NOT thread-safe.
|
||||
// Another common solution is global sdbus-c++ startup/shutdown functions, but that would be an intrusive change.
|
||||
|
||||
#ifdef __cpp_constinit
|
||||
constinit bool pseudoConnectionDestroyed{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
#else
|
||||
bool pseudoConnectionDestroyed{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
#endif
|
||||
/*constinit (C++20 keyword) */ static bool pseudoConnectionDestroyed{};
|
||||
|
||||
std::unique_ptr<internal::IConnection, void(*)(internal::IConnection*)> createPseudoConnection()
|
||||
std::unique_ptr<sdbus::internal::IConnection, void(*)(sdbus::internal::IConnection*)> createPseudoConnection()
|
||||
{
|
||||
auto deleter = [](internal::IConnection* con)
|
||||
auto deleter = [](sdbus::internal::IConnection* con)
|
||||
{
|
||||
delete con; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
delete con;
|
||||
pseudoConnectionDestroyed = true;
|
||||
};
|
||||
|
||||
return {internal::createPseudoConnection().release(), std::move(deleter)};
|
||||
}
|
||||
|
||||
internal::IConnection& getPseudoConnectionInstance()
|
||||
sdbus::internal::IConnection& getPseudoConnectionInstance()
|
||||
{
|
||||
static auto connection = createPseudoConnection();
|
||||
|
||||
if (pseudoConnectionDestroyed)
|
||||
{
|
||||
connection = createPseudoConnection(); // Phoenix rising from the ashes
|
||||
std::ignore = atexit([](){ connection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
|
||||
atexit([](){ connection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
|
||||
pseudoConnectionDestroyed = false;
|
||||
}
|
||||
|
||||
@@ -955,7 +913,7 @@ internal::IConnection& getPseudoConnectionInstance()
|
||||
return *connection;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
}
|
||||
|
||||
PlainMessage createPlainMessage()
|
||||
{
|
||||
@@ -963,8 +921,8 @@ PlainMessage createPlainMessage()
|
||||
// This is a bit of a hack, but it enables use to work with D-Bus message locally without
|
||||
// the need of D-Bus daemon. This is especially useful in unit tests of both sdbus-c++ and client code.
|
||||
// Additionally, it's light-weight and fast solution.
|
||||
const auto& connection = getPseudoConnectionInstance();
|
||||
auto& connection = getPseudoConnectionInstance();
|
||||
return connection.createPlainMessage();
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
+16
-14
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file MessageUtils.h
|
||||
*
|
||||
@@ -34,30 +34,32 @@ 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::ISdBus* sdbus)
|
||||
{
|
||||
return Msg{msg, connection};
|
||||
return _Msg{msg, sdbus};
|
||||
}
|
||||
|
||||
template<typename Msg>
|
||||
static Msg create(void *msg, internal::IConnection* connection, adopt_message_t)
|
||||
template<typename _Msg>
|
||||
static _Msg create(void *msg, internal::ISdBus* sdbus, adopt_message_t)
|
||||
{
|
||||
return Msg{msg, connection, adopt_message};
|
||||
return _Msg{msg, sdbus, adopt_message};
|
||||
}
|
||||
};
|
||||
} // namespace sdbus
|
||||
|
||||
PlainMessage createPlainMessage();
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_MESSAGEUTILS_H_ */
|
||||
|
||||
+43
-65
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Object.cpp
|
||||
*
|
||||
@@ -29,44 +29,36 @@
|
||||
#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(IConnection& connection, ObjectPath objectPath)
|
||||
Object::Object(sdbus::internal::IConnection& connection, std::string objectPath)
|
||||
: connection_(connection), objectPath_(std::move(objectPath))
|
||||
{
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_.c_str());
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
}
|
||||
|
||||
void Object::addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable)
|
||||
void Object::addVTable(std::string interfaceName, std::vector<VTableItem> vtable)
|
||||
{
|
||||
auto slot = Object::addVTable(std::move(interfaceName), std::move(vtable), return_slot);
|
||||
|
||||
vtables_.push_back(std::move(slot));
|
||||
}
|
||||
|
||||
Slot Object::addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable, return_slot_t)
|
||||
Slot Object::addVTable(std::string interfaceName, std::vector<VTableItem> vtable, return_slot_t)
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName.c_str());
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
|
||||
// 1st pass -- create vtable structure for internal sdbus-c++ purposes
|
||||
auto internalVTable = std::make_unique<VTable>(createInternalVTable(std::move(interfaceName), std::move(vtable)));
|
||||
@@ -75,55 +67,36 @@ Slot Object::addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtab
|
||||
internalVTable->sdbusVTable = createInternalSdBusVTable(*internalVTable);
|
||||
|
||||
// 3rd step -- register the vtable with sd-bus
|
||||
internalVTable->slot = connection_.addObjectVTable( objectPath_
|
||||
, internalVTable->interfaceName
|
||||
, internalVTable->sdbusVTable.data()
|
||||
, internalVTable.get()
|
||||
, return_slot );
|
||||
internalVTable->slot = connection_.addObjectVTable(objectPath_, internalVTable->interfaceName, &internalVTable->sdbusVTable[0], internalVTable.get());
|
||||
|
||||
// Return vtable wrapped in a Slot object
|
||||
return {internalVTable.release(), [](void *ptr){ delete static_cast<VTable*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return {internalVTable.release(), [](void *ptr){ delete static_cast<VTable*>(ptr); }};
|
||||
}
|
||||
|
||||
void Object::unregister()
|
||||
{
|
||||
vtables_.clear();
|
||||
objectManagerSlot_.reset();
|
||||
removeObjectManager();
|
||||
}
|
||||
|
||||
Signal Object::createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const
|
||||
sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::string& signalName)
|
||||
{
|
||||
return connection_.createSignal(objectPath_, interfaceName, signalName);
|
||||
}
|
||||
|
||||
Signal Object::createSignal(const char* interfaceName, const char* signalName) const
|
||||
{
|
||||
return connection_.createSignal(objectPath_.c_str(), interfaceName, signalName);
|
||||
}
|
||||
|
||||
void Object::emitSignal(const Signal& message)
|
||||
void Object::emitSignal(const sdbus::Signal& message)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid signal message provided", EINVAL);
|
||||
|
||||
message.send();
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector<PropertyName>& propNames)
|
||||
void Object::emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames)
|
||||
{
|
||||
connection_.emitPropertiesChangedSignal(objectPath_, interfaceName, propNames);
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const char* interfaceName, const std::vector<PropertyName>& propNames)
|
||||
{
|
||||
connection_.emitPropertiesChangedSignal(objectPath_.c_str(), interfaceName, propNames);
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const InterfaceName& interfaceName)
|
||||
{
|
||||
Object::emitPropertiesChangedSignal(interfaceName, {});
|
||||
}
|
||||
|
||||
void Object::emitPropertiesChangedSignal(const char* interfaceName)
|
||||
void Object::emitPropertiesChangedSignal(const std::string& interfaceName)
|
||||
{
|
||||
Object::emitPropertiesChangedSignal(interfaceName, {});
|
||||
}
|
||||
@@ -133,7 +106,7 @@ void Object::emitInterfacesAddedSignal()
|
||||
connection_.emitInterfacesAddedSignal(objectPath_);
|
||||
}
|
||||
|
||||
void Object::emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces)
|
||||
void Object::emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
connection_.emitInterfacesAddedSignal(objectPath_, interfaces);
|
||||
}
|
||||
@@ -143,7 +116,7 @@ void Object::emitInterfacesRemovedSignal()
|
||||
connection_.emitInterfacesRemovedSignal(objectPath_);
|
||||
}
|
||||
|
||||
void Object::emitInterfacesRemovedSignal(const std::vector<InterfaceName>& interfaces)
|
||||
void Object::emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
connection_.emitInterfacesRemovedSignal(objectPath_, interfaces);
|
||||
}
|
||||
@@ -153,9 +126,14 @@ void Object::addObjectManager()
|
||||
objectManagerSlot_ = connection_.addObjectManager(objectPath_, return_slot);
|
||||
}
|
||||
|
||||
Slot Object::addObjectManager(return_slot_t)
|
||||
void Object::removeObjectManager()
|
||||
{
|
||||
return connection_.addObjectManager(objectPath_, return_slot);
|
||||
objectManagerSlot_.reset();
|
||||
}
|
||||
|
||||
bool Object::hasObjectManager() const
|
||||
{
|
||||
return objectManagerSlot_ != nullptr;
|
||||
}
|
||||
|
||||
sdbus::IConnection& Object::getConnection() const
|
||||
@@ -163,7 +141,7 @@ sdbus::IConnection& Object::getConnection() const
|
||||
return connection_;
|
||||
}
|
||||
|
||||
const ObjectPath& Object::getObjectPath() const
|
||||
const std::string& Object::getObjectPath() const
|
||||
{
|
||||
return objectPath_;
|
||||
}
|
||||
@@ -173,7 +151,7 @@ Message Object::getCurrentlyProcessedMessage() const
|
||||
return connection_.getCurrentlyProcessedMessage();
|
||||
}
|
||||
|
||||
Object::VTable Object::createInternalVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable)
|
||||
Object::VTable Object::createInternalVTable(std::string interfaceName, std::vector<VTableItem> vtable)
|
||||
{
|
||||
VTable internalVTable;
|
||||
|
||||
@@ -189,9 +167,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& 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; });
|
||||
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; });
|
||||
|
||||
internalVTable.object = this;
|
||||
|
||||
@@ -205,7 +183,7 @@ void Object::writeInterfaceFlagsToVTable(InterfaceFlagsVTableItem flags, VTable&
|
||||
|
||||
void Object::writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(method.name.c_str());
|
||||
SDBUS_CHECK_MEMBER_NAME(method.name);
|
||||
SDBUS_THROW_ERROR_IF(!method.callbackHandler, "Invalid method callback provided", EINVAL);
|
||||
|
||||
vtable.methods.push_back({ std::move(method.name)
|
||||
@@ -218,7 +196,7 @@ void Object::writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable)
|
||||
|
||||
void Object::writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(signal.name.c_str());
|
||||
SDBUS_CHECK_MEMBER_NAME(signal.name);
|
||||
|
||||
vtable.signals.push_back({ std::move(signal.name)
|
||||
, std::move(signal.signature)
|
||||
@@ -228,7 +206,7 @@ void Object::writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable)
|
||||
|
||||
void Object::writePropertyRecordToVTable(PropertyVTableItem property, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(property.name.c_str());
|
||||
SDBUS_CHECK_MEMBER_NAME(property.name);
|
||||
SDBUS_THROW_ERROR_IF(!property.getter && !property.setter, "Invalid property callbacks provided", EINVAL);
|
||||
|
||||
vtable.properties.push_back({ std::move(property.name)
|
||||
@@ -263,8 +241,8 @@ void Object::startSdBusVTable(const Flags& interfaceFlags, std::vector<sd_bus_vt
|
||||
void Object::writeMethodRecordToSdBusVTable(const VTable::MethodItem& method, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
auto vtableItem = createSdBusVTableMethodItem( method.name.c_str()
|
||||
, method.inputSignature.c_str()
|
||||
, method.outputSignature.c_str()
|
||||
, method.inputArgs.c_str()
|
||||
, method.outputArgs.c_str()
|
||||
, method.paramNames.c_str()
|
||||
, &Object::sdbus_method_callback
|
||||
, method.flags.toSdBusMethodFlags() );
|
||||
@@ -300,7 +278,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)
|
||||
const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, const std::string& methodName)
|
||||
{
|
||||
auto it = std::lower_bound(vtable.methods.begin(), vtable.methods.end(), methodName, [](const auto& methodItem, const auto& methodName)
|
||||
{
|
||||
@@ -310,7 +288,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)
|
||||
const Object::VTable::PropertyItem* Object::findProperty(const VTable& vtable, const std::string& propertyName)
|
||||
{
|
||||
auto it = std::lower_bound(vtable.properties.begin(), vtable.properties.end(), propertyName, [](const auto& propertyItem, const auto& propertyName)
|
||||
{
|
||||
@@ -334,7 +312,7 @@ int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData,
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_);
|
||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
const auto* methodItem = findMethod(*vtable, message.getMemberName());
|
||||
assert(methodItem != nullptr);
|
||||
@@ -367,7 +345,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &vtable->object->connection_);
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->getCallback(reply); }, retError);
|
||||
|
||||
@@ -390,23 +368,23 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
|
||||
assert(propertyItem != nullptr);
|
||||
assert(propertyItem->setCallback);
|
||||
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &vtable->object->connection_);
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->setCallback(std::move(value)); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::unique_ptr<IObject> createObject(IConnection& connection, ObjectPath objectPath)
|
||||
std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, std::string objectPath)
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(&connection);
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
return std::make_unique<internal::Object>(*sdbusConnection, std::move(objectPath));
|
||||
return std::make_unique<sdbus::internal::Object>(*sdbusConnection, std::move(objectPath));
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
+34
-44
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Object.h
|
||||
*
|
||||
@@ -29,54 +29,43 @@
|
||||
|
||||
#include "sdbus-c++/IObject.h"
|
||||
|
||||
#include "sdbus-c++/Types.h"
|
||||
#include "IConnection.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#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(IConnection& connection, ObjectPath objectPath);
|
||||
Object(sdbus::internal::IConnection& connection, std::string objectPath);
|
||||
|
||||
void addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable) override;
|
||||
Slot addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable, return_slot_t) override;
|
||||
void addVTable(std::string interfaceName, std::vector<VTableItem> vtable) override;
|
||||
Slot addVTable(std::string interfaceName, std::vector<VTableItem> vtable, return_slot_t) override;
|
||||
void unregister() 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 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;
|
||||
void emitPropertiesChangedSignal(const char* interfaceName) override;
|
||||
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
||||
void emitSignal(const sdbus::Signal& message) override;
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& propNames) override;
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName) override;
|
||||
void emitInterfacesAddedSignal() override;
|
||||
void emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces) override;
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces) override;
|
||||
void emitInterfacesRemovedSignal() override;
|
||||
void emitInterfacesRemovedSignal(const std::vector<InterfaceName>& interfaces) override;
|
||||
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces) override;
|
||||
|
||||
void addObjectManager() override;
|
||||
[[nodiscard]] Slot addObjectManager(return_slot_t) override;
|
||||
void removeObjectManager() override;
|
||||
[[nodiscard]] bool hasObjectManager() const override;
|
||||
|
||||
[[nodiscard]] sdbus::IConnection& getConnection() const override;
|
||||
[[nodiscard]] const ObjectPath& getObjectPath() const override;
|
||||
[[nodiscard]] const std::string& getObjectPath() const override;
|
||||
[[nodiscard]] Message getCurrentlyProcessedMessage() const override;
|
||||
|
||||
private:
|
||||
@@ -85,14 +74,14 @@ namespace sdbus::internal {
|
||||
// An interface can have any number of vtables attached to it, not only one.
|
||||
struct VTable
|
||||
{
|
||||
InterfaceName interfaceName;
|
||||
std::string interfaceName;
|
||||
Flags interfaceFlags;
|
||||
|
||||
struct MethodItem
|
||||
{
|
||||
MethodName name;
|
||||
Signature inputSignature;
|
||||
Signature outputSignature;
|
||||
std::string name;
|
||||
std::string inputArgs;
|
||||
std::string outputArgs;
|
||||
std::string paramNames;
|
||||
method_callback callback;
|
||||
Flags flags;
|
||||
@@ -102,8 +91,8 @@ namespace sdbus::internal {
|
||||
|
||||
struct SignalItem
|
||||
{
|
||||
SignalName name;
|
||||
Signature signature;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::string paramNames;
|
||||
Flags flags;
|
||||
};
|
||||
@@ -112,8 +101,8 @@ namespace sdbus::internal {
|
||||
|
||||
struct PropertyItem
|
||||
{
|
||||
PropertyName name;
|
||||
Signature signature;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
property_get_callback getCallback;
|
||||
property_set_callback setCallback;
|
||||
Flags flags;
|
||||
@@ -132,21 +121,21 @@ namespace sdbus::internal {
|
||||
Slot slot;
|
||||
};
|
||||
|
||||
VTable createInternalVTable(InterfaceName interfaceName, std::vector<VTableItem> 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);
|
||||
VTable createInternalVTable(std::string 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 std::vector<sd_bus_vtable> createInternalSdBusVTable(const VTable& vtable);
|
||||
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 const VTable::MethodItem* findMethod(const VTable& vtable, const std::string& methodName);
|
||||
static const VTable::PropertyItem* findProperty(const VTable& vtable, const std::string& propertyName);
|
||||
|
||||
static std::string paramNamesToString(const std::vector<std::string>& paramNames);
|
||||
|
||||
@@ -166,12 +155,13 @@ namespace sdbus::internal {
|
||||
, void *userData
|
||||
, sd_bus_error *retError );
|
||||
|
||||
IConnection& connection_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
ObjectPath objectPath_;
|
||||
private:
|
||||
sdbus::internal::IConnection& connection_;
|
||||
std::string objectPath_;
|
||||
std::vector<Slot> vtables_;
|
||||
Slot objectManagerSlot_;
|
||||
};
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_OBJECT_H_ */
|
||||
|
||||
+101
-242
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Proxy.cpp
|
||||
*
|
||||
@@ -28,135 +28,87 @@
|
||||
|
||||
#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(IConnection& connection, ServiceName destination, ObjectPath objectPath)
|
||||
: connection_(&connection, [](IConnection *){ /* Intentionally left empty */ })
|
||||
Proxy::Proxy(sdbus::internal::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_.c_str());
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_.c_str());
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_);
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
|
||||
// The connection is not ours only, it is owned and managed by the user and we just reference
|
||||
// it here, so we expect the client to manage the event loop upon this connection themselves.
|
||||
}
|
||||
|
||||
Proxy::Proxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath )
|
||||
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
: connection_(std::move(connection))
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_.c_str());
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_.c_str());
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_);
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
|
||||
// The connection is ours only, i.e. it's us who has to manage the event loop upon this connection,
|
||||
// in order that we get and process signals, async call replies, and other messages from D-Bus.
|
||||
connection_->enterEventLoopAsync();
|
||||
}
|
||||
|
||||
Proxy::Proxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath
|
||||
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
: connection_(std::move(connection))
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_.c_str());
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_.c_str());
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_);
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
|
||||
// Even though the connection is ours only, we don't start an event loop thread.
|
||||
// This proxy is meant to be created, used for simple synchronous D-Bus call(s) and then dismissed.
|
||||
}
|
||||
|
||||
MethodCall Proxy::createMethodCall(const InterfaceName& interfaceName, const MethodName& methodName) const
|
||||
MethodCall Proxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
||||
{
|
||||
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
|
||||
}
|
||||
|
||||
MethodCall Proxy::createMethodCall(const char* interfaceName, const char* methodName) const
|
||||
{
|
||||
return connection_->createMethodCall(destination_.c_str(), objectPath_.c_str(), interfaceName, methodName);
|
||||
}
|
||||
|
||||
MethodReply Proxy::callMethod(const MethodCall& message)
|
||||
{
|
||||
return Proxy::callMethod(message, /*timeout*/ 0);
|
||||
}
|
||||
|
||||
MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid method call message provided", EINVAL);
|
||||
|
||||
return message.send(timeout);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return Proxy::callMethodAsync(message, std::move(asyncReplyCallback), /*timeout*/ 0, return_slot);
|
||||
return connection_->callMethod(message, 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 });
|
||||
auto callback = (void*)&Proxy::sdbus_async_reply_handler;
|
||||
auto callData = std::make_shared<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback)});
|
||||
auto weakData = std::weak_ptr<AsyncCalls::CallData>{callData};
|
||||
|
||||
asyncCallInfo->slot = message.send(reinterpret_cast<void*>(&Proxy::sdbus_async_reply_handler), asyncCallInfo.get(), timeout, return_slot);
|
||||
callData->slot = connection_->callMethod(message, callback, callData.get(), timeout);
|
||||
|
||||
auto asyncCallInfoWeakPtr = std::weak_ptr{asyncCallInfo};
|
||||
pendingAsyncCalls_.addCall(std::move(callData));
|
||||
|
||||
floatingAsyncCallSlots_.push_back(std::move(asyncCallInfo));
|
||||
|
||||
return PendingAsyncCall{asyncCallInfoWeakPtr};
|
||||
}
|
||||
|
||||
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(reinterpret_cast<void*>(&Proxy::sdbus_async_reply_handler), asyncCallInfo.get(), timeout, return_slot);
|
||||
|
||||
return {asyncCallInfo.release(), [](void *ptr){ delete static_cast<AsyncCallInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
// TODO: Instead of PendingAsyncCall consider using Slot implementation for simplicity and consistency
|
||||
return {weakData};
|
||||
}
|
||||
|
||||
std::future<MethodReply> Proxy::callMethodAsync(const MethodCall& message, with_future_t)
|
||||
@@ -182,40 +134,8 @@ 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 )
|
||||
{
|
||||
Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler));
|
||||
}
|
||||
|
||||
void Proxy::registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
void Proxy::registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler )
|
||||
{
|
||||
auto slot = Proxy::registerSignalHandler(interfaceName, signalName, std::move(signalHandler), return_slot);
|
||||
@@ -223,16 +143,8 @@ void Proxy::registerSignalHandler( const char* interfaceName
|
||||
floatingSignalSlots_.push_back(std::move(slot));
|
||||
}
|
||||
|
||||
Slot Proxy::registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t )
|
||||
{
|
||||
return Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler), return_slot);
|
||||
}
|
||||
|
||||
Slot Proxy::registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
Slot Proxy::registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t )
|
||||
{
|
||||
@@ -242,20 +154,19 @@ Slot Proxy::registerSignalHandler( const char* interfaceName
|
||||
|
||||
auto signalInfo = std::make_unique<SignalInfo>(SignalInfo{std::move(signalHandler), *this, {}});
|
||||
|
||||
signalInfo->slot = connection_->registerSignalHandler( destination_.c_str()
|
||||
, objectPath_.c_str()
|
||||
signalInfo->slot = connection_->registerSignalHandler( destination_
|
||||
, objectPath_
|
||||
, interfaceName
|
||||
, signalName
|
||||
, &Proxy::sdbus_signal_handler
|
||||
, signalInfo.get()
|
||||
, return_slot );
|
||||
, signalInfo.get() );
|
||||
|
||||
return {signalInfo.release(), [](void *ptr){ delete static_cast<SignalInfo*>(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return {signalInfo.release(), [](void *ptr){ delete static_cast<SignalInfo*>(ptr); }};
|
||||
}
|
||||
|
||||
void Proxy::unregister()
|
||||
{
|
||||
floatingAsyncCallSlots_.clear();
|
||||
pendingAsyncCalls_.clear();
|
||||
floatingSignalSlots_.clear();
|
||||
}
|
||||
|
||||
@@ -264,7 +175,7 @@ sdbus::IConnection& Proxy::getConnection() const
|
||||
return *connection_;
|
||||
}
|
||||
|
||||
const ObjectPath& Proxy::getObjectPath() const
|
||||
const std::string& Proxy::getObjectPath() const
|
||||
{
|
||||
return objectPath_;
|
||||
}
|
||||
@@ -276,32 +187,32 @@ Message Proxy::getCurrentlyProcessedMessage() const
|
||||
|
||||
int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
|
||||
{
|
||||
auto* asyncCallInfo = static_cast<AsyncCallInfo*>(userData);
|
||||
assert(asyncCallInfo != nullptr);
|
||||
assert(asyncCallInfo->callback);
|
||||
auto& proxy = asyncCallInfo->proxy;
|
||||
auto* asyncCallData = static_cast<AsyncCalls::CallData*>(userData);
|
||||
assert(asyncCallData != nullptr);
|
||||
assert(asyncCallData->callback);
|
||||
auto& proxy = asyncCallData->proxy;
|
||||
|
||||
// We are removing the CallData item at the complete scope exit, after the callback has been invoked.
|
||||
// We can't do it earlier (before callback invocation for example), because CallBack data (slot release)
|
||||
// is the synchronization point between callback invocation and Proxy::unregister.
|
||||
SCOPE_EXIT
|
||||
{
|
||||
proxy.floatingAsyncCallSlots_.erase(asyncCallInfo);
|
||||
proxy.pendingAsyncCalls_.removeCall(asyncCallData);
|
||||
};
|
||||
|
||||
auto message = Message::Factory::create<MethodReply>(sdbusMessage, proxy.connection_.get());
|
||||
auto message = Message::Factory::create<MethodReply>(sdbusMessage, &proxy.connection_->getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&]
|
||||
{
|
||||
const auto* error = sd_bus_message_get_error(sdbusMessage);
|
||||
if (error == nullptr)
|
||||
{
|
||||
asyncCallInfo->callback(std::move(message), {});
|
||||
asyncCallData->callback(std::move(message), {});
|
||||
}
|
||||
else
|
||||
{
|
||||
Error exception(Error::Name{error->name}, error->message);
|
||||
asyncCallInfo->callback(std::move(message), std::move(exception));
|
||||
Error exception(error->name, error->message);
|
||||
asyncCallData->callback(std::move(message), std::move(exception));
|
||||
}
|
||||
}, retError);
|
||||
|
||||
@@ -314,71 +225,29 @@ int Proxy::sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd
|
||||
assert(signalInfo != nullptr);
|
||||
assert(signalInfo->callback);
|
||||
|
||||
auto message = Message::Factory::create<Signal>(sdbusMessage, signalInfo->proxy.connection_.get());
|
||||
// TODO: Hide Message factory invocation under Connection API (tell, don't ask principle), then we can remove getSdBusInterface()
|
||||
auto message = Message::Factory::create<Signal>(sdbusMessage, &signalInfo->proxy.connection_->getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ signalInfo->callback(std::move(message)); }, retError);
|
||||
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
Proxy::FloatingAsyncCallSlots::~FloatingAsyncCallSlots()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void Proxy::FloatingAsyncCallSlots::push_back(std::shared_ptr<AsyncCallInfo> asyncCallInfo)
|
||||
{
|
||||
const std::lock_guard lock(mutex_);
|
||||
if (!asyncCallInfo->finished) // The call may have finished in the meantime
|
||||
slots_.emplace_back(std::move(asyncCallInfo));
|
||||
}
|
||||
|
||||
void Proxy::FloatingAsyncCallSlots::erase(AsyncCallInfo* info)
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
info->finished = true;
|
||||
auto it = std::find_if(slots_.begin(), slots_.end(), [info](auto const& entry){ return entry.get() == info; });
|
||||
if (it != slots_.end())
|
||||
{
|
||||
auto callInfo = std::move(*it);
|
||||
slots_.erase(it);
|
||||
lock.unlock();
|
||||
|
||||
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
|
||||
// out of the `mutex_' critical section here, because if the `removeCall` is called by some
|
||||
// thread and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
}
|
||||
|
||||
void Proxy::FloatingAsyncCallSlots::clear()
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
auto asyncCallSlots = std::move(slots_);
|
||||
slots_ = {};
|
||||
lock.unlock();
|
||||
|
||||
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
|
||||
// out of the `mutex_' critical section here, because if the `clear` is called by some thread
|
||||
// and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
PendingAsyncCall::PendingAsyncCall(std::weak_ptr<void> callInfo)
|
||||
: callInfo_(std::move(callInfo))
|
||||
PendingAsyncCall::PendingAsyncCall(std::weak_ptr<void> callData)
|
||||
: callData_(std::move(callData))
|
||||
{
|
||||
}
|
||||
|
||||
void PendingAsyncCall::cancel()
|
||||
{
|
||||
if (auto ptr = callInfo_.lock(); ptr != nullptr)
|
||||
if (auto ptr = callData_.lock(); ptr != nullptr)
|
||||
{
|
||||
auto* asyncCallInfo = static_cast<internal::Proxy::AsyncCallInfo*>(ptr.get());
|
||||
asyncCallInfo->proxy.floatingAsyncCallSlots_.erase(asyncCallInfo);
|
||||
auto* callData = static_cast<internal::Proxy::AsyncCalls::CallData*>(ptr.get());
|
||||
callData->proxy.pendingAsyncCalls_.removeCall(callData);
|
||||
|
||||
// At this point, the callData item is being deleted, leading to the release of the
|
||||
// sd-bus slot pointer. This release locks the global sd-bus mutex. If the async
|
||||
@@ -389,91 +258,81 @@ void PendingAsyncCall::cancel()
|
||||
|
||||
bool PendingAsyncCall::isPending() const
|
||||
{
|
||||
return !callInfo_.expired();
|
||||
return !callData_.expired();
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
std::unique_ptr<IProxy> createProxy( IConnection& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath )
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( IConnection& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(&connection);
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
return std::make_unique<internal::Proxy>( *sdbusConnection
|
||||
return std::make_unique<sdbus::internal::Proxy>( *sdbusConnection
|
||||
, std::move(destination)
|
||||
, std::move(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 )
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<internal::IConnection*>(connection.release());
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
return std::make_unique<internal::Proxy>( std::unique_ptr<internal::IConnection>(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath) );
|
||||
connection.release();
|
||||
|
||||
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
// 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<internal::IConnection*>(connection.release());
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
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<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<IProxy> createProxy( ServiceName destination
|
||||
, ObjectPath objectPath )
|
||||
{
|
||||
auto connection = createBusConnection();
|
||||
|
||||
auto sdbusConnection = std::unique_ptr<internal::IConnection>(dynamic_cast<internal::IConnection*>(connection.release()));
|
||||
assert(sdbusConnection != nullptr);
|
||||
|
||||
return std::make_unique<internal::Proxy>( std::move(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
std::unique_ptr<IProxy> createProxy( ServiceName destination
|
||||
, ObjectPath objectPath
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
{
|
||||
auto connection = createBusConnection();
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
auto sdbusConnection = std::unique_ptr<internal::IConnection>(dynamic_cast<internal::IConnection*>(connection.release()));
|
||||
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 );
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
|
||||
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
|
||||
assert(sdbusConnection != nullptr);
|
||||
|
||||
return std::make_unique<internal::Proxy>( std::move(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath)
|
||||
, dont_run_event_loop_thread );
|
||||
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
std::unique_ptr<IProxy> createLightWeightProxy(ServiceName destination, ObjectPath objectPath)
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
{
|
||||
return createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread);
|
||||
auto connection = sdbus::createBusConnection();
|
||||
|
||||
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::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 );
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
}
|
||||
|
||||
+80
-70
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Proxy.h
|
||||
*
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "sdbus-c++/IProxy.h"
|
||||
|
||||
#include "IConnection.h"
|
||||
#include "sdbus-c++/Types.h"
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
@@ -45,110 +44,121 @@ namespace sdbus::internal {
|
||||
: public IProxy
|
||||
{
|
||||
public:
|
||||
Proxy( IConnection& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
Proxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath );
|
||||
Proxy( std::unique_ptr<IConnection>&& connection
|
||||
, ServiceName destination
|
||||
, ObjectPath objectPath
|
||||
Proxy( sdbus::internal::IConnection& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
|
||||
[[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;
|
||||
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
||||
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
||||
PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) override;
|
||||
Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, return_slot_t ) override;
|
||||
PendingAsyncCall callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, uint64_t timeout ) override;
|
||||
Slot callMethodAsync( const MethodCall& message
|
||||
, async_reply_handler asyncReplyCallback
|
||||
, uint64_t timeout
|
||||
, return_slot_t ) override;
|
||||
PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) 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
|
||||
void registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler ) override;
|
||||
void registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
, signal_handler signalHandler ) override;
|
||||
Slot registerSignalHandler( const InterfaceName& interfaceName
|
||||
, const SignalName& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t ) override;
|
||||
Slot registerSignalHandler( const char* interfaceName
|
||||
, const char* signalName
|
||||
Slot registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler
|
||||
, return_slot_t ) override;
|
||||
void unregister() override;
|
||||
|
||||
[[nodiscard]] sdbus::IConnection& getConnection() const override;
|
||||
[[nodiscard]] const ObjectPath& getObjectPath() const override;
|
||||
[[nodiscard]] const std::string& getObjectPath() const override;
|
||||
[[nodiscard]] Message getCurrentlyProcessedMessage() const override;
|
||||
|
||||
private:
|
||||
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<IConnection, std::function<void(IConnection*)>> connection_;
|
||||
ServiceName destination_;
|
||||
ObjectPath objectPath_;
|
||||
std::unique_ptr< sdbus::internal::IConnection
|
||||
, std::function<void(sdbus::internal::IConnection*)>
|
||||
> connection_;
|
||||
std::string destination_;
|
||||
std::string objectPath_;
|
||||
|
||||
std::vector<Slot> floatingSignalSlots_;
|
||||
|
||||
struct SignalInfo
|
||||
{
|
||||
signal_handler callback;
|
||||
Proxy& proxy; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
Proxy& proxy;
|
||||
Slot slot;
|
||||
};
|
||||
|
||||
struct AsyncCallInfo
|
||||
{
|
||||
async_reply_handler callback;
|
||||
Proxy& proxy; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
Slot slot;
|
||||
bool finished{false};
|
||||
bool floating;
|
||||
};
|
||||
|
||||
// Container keeping track of pending async calls
|
||||
class FloatingAsyncCallSlots
|
||||
// We need to keep track of pending async calls. When the proxy is being destructed, we must
|
||||
// remove all slots of these pending calls, otherwise in case when the connection outlives
|
||||
// the proxy, we might get async reply handlers invoked for pending async calls after the proxy
|
||||
// has been destroyed, which is a free ticket into the realm of undefined behavior.
|
||||
class AsyncCalls
|
||||
{
|
||||
public:
|
||||
FloatingAsyncCallSlots() = default;
|
||||
FloatingAsyncCallSlots(const FloatingAsyncCallSlots&) = delete;
|
||||
FloatingAsyncCallSlots& operator=(const FloatingAsyncCallSlots&) = delete;
|
||||
FloatingAsyncCallSlots(FloatingAsyncCallSlots&& other) = delete;
|
||||
FloatingAsyncCallSlots& operator=(FloatingAsyncCallSlots&&) = delete;
|
||||
~FloatingAsyncCallSlots();
|
||||
struct CallData
|
||||
{
|
||||
Proxy& proxy;
|
||||
async_reply_handler callback;
|
||||
Slot slot{};
|
||||
bool finished{false};
|
||||
};
|
||||
|
||||
void push_back(std::shared_ptr<AsyncCallInfo> asyncCallInfo);
|
||||
void erase(AsyncCallInfo* info);
|
||||
void clear();
|
||||
~AsyncCalls()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void addCall(std::shared_ptr<CallData> asyncCallData)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
if (!asyncCallData->finished) // The call may have finished in the meantime
|
||||
calls_.emplace_back(std::move(asyncCallData));
|
||||
}
|
||||
|
||||
void removeCall(CallData* data)
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
data->finished = true;
|
||||
if (auto it = std::find_if(calls_.begin(), calls_.end(), [data](auto const& entry){ return entry.get() == data; }); it != calls_.end())
|
||||
{
|
||||
auto callData = std::move(*it);
|
||||
calls_.erase(it);
|
||||
lock.unlock();
|
||||
|
||||
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
|
||||
// out of the `mutex_' critical section here, because if the `removeCall` is called by some
|
||||
// thread and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
auto asyncCallSlots = std::move(calls_);
|
||||
calls_ = {};
|
||||
lock.unlock();
|
||||
|
||||
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
|
||||
// out of the `mutex_' critical section here, because if the `clear` is called by some thread
|
||||
// and at the same time Proxy's async reply handler (which already holds global sd-bus
|
||||
// mutex) is in progress in a different thread, we get double-mutex deadlock.
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::deque<std::shared_ptr<AsyncCallInfo>> slots_;
|
||||
};
|
||||
|
||||
FloatingAsyncCallSlots floatingAsyncCallSlots_;
|
||||
std::deque<std::shared_ptr<CallData>> calls_;
|
||||
} pendingAsyncCalls_;
|
||||
};
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_INTERNAL_PROXY_H_ */
|
||||
|
||||
+16
-21
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ScopeGuard.h
|
||||
*
|
||||
@@ -30,8 +30,6 @@
|
||||
#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
|
||||
@@ -107,22 +105,21 @@ namespace sdbus::internal {
|
||||
}
|
||||
};
|
||||
|
||||
template <class Fun, typename Tag>
|
||||
template <class _Fun, typename _Tag>
|
||||
class ScopeGuard
|
||||
{
|
||||
public:
|
||||
explicit ScopeGuard(Fun fun) : fnc_(std::move(fun))
|
||||
ScopeGuard(_Fun f) : fnc_(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
ScopeGuard() = delete;
|
||||
ScopeGuard(const ScopeGuard&) = delete;
|
||||
ScopeGuard& operator=(const ScopeGuard&) = delete;
|
||||
ScopeGuard(ScopeGuard&& rhs) noexcept : fnc_(std::move(rhs.fnc_)), exceptions_(rhs.exceptions_), active_(rhs.active_)
|
||||
ScopeGuard(ScopeGuard&& rhs) : fnc_(std::move(rhs.fnc_)), active_(rhs.active_), exceptions_(rhs.exceptions_)
|
||||
{
|
||||
rhs.dismiss();
|
||||
}
|
||||
ScopeGuard& operator=(ScopeGuard&&) = delete;
|
||||
|
||||
void dismiss()
|
||||
{
|
||||
@@ -131,35 +128,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)
|
||||
@@ -170,6 +167,4 @@ namespace sdbus::internal {
|
||||
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
|
||||
#endif
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
|
||||
#endif /* SDBUS_CPP_INTERNAL_SCOPEGUARD_H_ */
|
||||
|
||||
+100
-106
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file SdBus.cpp
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
@@ -26,150 +26,155 @@
|
||||
*/
|
||||
|
||||
#include "SdBus.h"
|
||||
#include "sdbus-c++/Error.h" // NOLINT(misc-include-cleaner)
|
||||
#include SDBUS_HEADER
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <sys/types.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
|
||||
namespace sdbus::internal {
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *msg)
|
||||
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *m)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_ref(msg);
|
||||
return ::sd_bus_message_ref(m);
|
||||
}
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *msg)
|
||||
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_unref(msg);
|
||||
return ::sd_bus_message_unref(m);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *msg, uint64_t *cookie)
|
||||
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
auto r = ::sd_bus_send(bus, msg, cookie);
|
||||
auto r = ::sd_bus_send(bus, m, cookie);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
// Make sure long messages are not only stored in outgoing queues but also really sent out
|
||||
// TODO: This is a workaround. We should not block here until everything is physically sent out.
|
||||
// Refactor: if sd_bus_get_n_queued_write() > 0 then wake up event loop through event fd
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *msg, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
|
||||
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_call(bus, msg, usec, ret_error, reply);
|
||||
return ::sd_bus_call(bus, m, usec, ret_error, reply);
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
auto r = ::sd_bus_call_async(bus, slot, msg, callback, userdata, usec);
|
||||
auto r = ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
// Make sure long messages are not only stored in outgoing queues but also really sent out
|
||||
// TODO: This is a workaround. We should not block here until everything is physically sent out.
|
||||
// Refactor: if sd_bus_get_n_queued_write() > 0 then wake up event loop through event fd
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **msg, uint8_t type)
|
||||
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new(bus, msg, type);
|
||||
return ::sd_bus_message_new(bus, m, type);
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_call(bus, msg, destination, path, interface, member);
|
||||
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **msg, const char *path, const char *interface, const char *member)
|
||||
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_signal(bus, msg, path, interface, member);
|
||||
return ::sd_bus_message_new_signal(bus, m, path, interface, member);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **msg)
|
||||
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_return(call, msg);
|
||||
return ::sd_bus_message_new_method_return(call, m);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **msg, const sd_bus_error *err)
|
||||
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_new_method_error(call, msg, err);
|
||||
return ::sd_bus_message_new_method_error(call, m, e);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_set_method_call_timeout(sd_bus *bus, uint64_t usec)
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_set_method_call_timeout(bus, usec);
|
||||
#else
|
||||
(void)bus;
|
||||
(void)usec;
|
||||
throw Error(Error::Name{SD_BUS_ERROR_NOT_SUPPORTED}, "Setting general method call timeout not supported by underlying version of libsystemd");
|
||||
throw sdbus::Error(SD_BUS_ERROR_NOT_SUPPORTED, "Setting general method call timeout not supported by underlying version of libsystemd");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_get_method_call_timeout(sd_bus *bus, uint64_t *ret)
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_get_method_call_timeout(bus, ret);
|
||||
#else
|
||||
(void)bus;
|
||||
(void)ret;
|
||||
throw Error(Error::Name{SD_BUS_ERROR_NOT_SUPPORTED}, "Getting general method call timeout not supported by underlying version of libsystemd");
|
||||
throw sdbus::Error(SD_BUS_ERROR_NOT_SUPPORTED, "Getting general method call timeout not supported by underlying version of libsystemd");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
|
||||
}
|
||||
@@ -201,14 +206,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); // NOLINT(readability-implicit-bool-conversion)
|
||||
r = ::sd_bus_set_bus_client(bus, true);
|
||||
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); // NOLINT(readability-implicit-bool-conversion)
|
||||
r = ::sd_bus_set_trusted(bus, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -280,7 +285,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); // NOLINT(readability-implicit-bool-conversion)
|
||||
r = ::sd_bus_set_server(bus, true, id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -307,63 +312,62 @@ 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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_slot_unref(slot);
|
||||
}
|
||||
@@ -378,11 +382,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 **msg)
|
||||
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_process(bus, msg);
|
||||
return ::sd_bus_process(bus, r);
|
||||
}
|
||||
|
||||
sd_bus_message* SdBus::sd_bus_get_current_message(sd_bus *bus)
|
||||
@@ -392,7 +396,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)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
auto r = ::sd_bus_get_fd(bus);
|
||||
if (r < 0)
|
||||
@@ -409,14 +413,11 @@ 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) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
int SdBus::sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
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);
|
||||
|
||||
return std::min(r1, r2);
|
||||
return ::sd_bus_get_n_queued_read(bus, ret);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_flush(sd_bus *bus)
|
||||
@@ -439,81 +440,74 @@ sd_bus* SdBus::sd_bus_close_unref(sd_bus *bus)
|
||||
#endif
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_set_destination(sd_bus_message *msg, const char *destination)
|
||||
int SdBus::sd_bus_message_set_destination(sd_bus_message *m, const char *destination)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_message_set_destination(msg, destination);
|
||||
return ::sd_bus_message_set_destination(m, destination);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_query_sender_creds(sd_bus_message *msg, uint64_t mask, sd_bus_creds **creds)
|
||||
int SdBus::sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_query_sender_creds(msg, mask, creds);
|
||||
return ::sd_bus_query_sender_creds(m, mask, c);
|
||||
}
|
||||
|
||||
sd_bus_creds* SdBus::sd_bus_creds_ref(sd_bus_creds *creds)
|
||||
sd_bus_creds* SdBus::sd_bus_creds_unref(sd_bus_creds *c)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_ref(creds);
|
||||
return ::sd_bus_creds_unref(c);
|
||||
}
|
||||
|
||||
sd_bus_creds* SdBus::sd_bus_creds_unref(sd_bus_creds *creds)
|
||||
int SdBus::sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_unref(creds);
|
||||
return ::sd_bus_creds_get_pid(c, pid);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_pid(sd_bus_creds *creds, pid_t *pid)
|
||||
int SdBus::sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_pid(creds, pid);
|
||||
return ::sd_bus_creds_get_uid(c, uid);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_uid(sd_bus_creds *creds, uid_t *uid)
|
||||
int SdBus::sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_uid(creds, uid);
|
||||
return ::sd_bus_creds_get_euid(c, euid);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_euid(sd_bus_creds *creds, uid_t *euid)
|
||||
int SdBus::sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_euid(creds, euid);
|
||||
return ::sd_bus_creds_get_gid(c, gid);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_gid(sd_bus_creds *creds, gid_t *gid)
|
||||
int SdBus::sd_bus_creds_get_egid(sd_bus_creds *c, uid_t *egid)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_gid(creds, gid);
|
||||
return ::sd_bus_creds_get_egid(c, egid);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_egid(sd_bus_creds *creds, uid_t *egid)
|
||||
int SdBus::sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_egid(creds, egid);
|
||||
return ::sd_bus_creds_get_supplementary_gids(c, gids);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_supplementary_gids(sd_bus_creds *creds, const gid_t **gids)
|
||||
int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_supplementary_gids(creds, gids);
|
||||
return ::sd_bus_creds_get_selinux_context(c, label);
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *creds, const char **label)
|
||||
{
|
||||
const std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_creds_get_selinux_context(creds, label);
|
||||
}
|
||||
|
||||
} // namespace sdbus::internal
|
||||
|
||||
+56
-57
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file SdBus.h
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
@@ -36,75 +36,74 @@ namespace sdbus::internal {
|
||||
class SdBus final : public ISdBus
|
||||
{
|
||||
public:
|
||||
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 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;
|
||||
|
||||
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_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_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_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_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_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_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_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_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_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_new(sd_bus **ret) override;
|
||||
int sd_bus_start(sd_bus *bus) override;
|
||||
virtual int sd_bus_new(sd_bus **ret) override;
|
||||
virtual int sd_bus_start(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_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_read(sd_bus *bus, uint64_t *ret) 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_message_set_destination(sd_bus_message *msg, const char *destination) override;
|
||||
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) 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_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **c) override;
|
||||
virtual sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c) 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;
|
||||
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;
|
||||
|
||||
private:
|
||||
std::recursive_mutex sdbusMutex_;
|
||||
};
|
||||
|
||||
} // namespace sdbus::internal
|
||||
}
|
||||
|
||||
#endif // SDBUS_CXX_SDBUS_H
|
||||
#endif //SDBUS_C_SDBUS_H
|
||||
|
||||
+10
-6
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types.cpp
|
||||
*
|
||||
@@ -24,10 +24,12 @@
|
||||
* 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 "sdbus-c++/Error.h"
|
||||
|
||||
#include "MessageUtils.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <system_error>
|
||||
#include SDBUS_HEADER
|
||||
@@ -53,10 +55,12 @@ void Variant::deserializeFrom(Message& msg)
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
const char* Variant::peekValueType() const
|
||||
std::string Variant::peekValueType() const
|
||||
{
|
||||
msg_.rewind(false);
|
||||
auto [type, contents] = msg_.peekType();
|
||||
std::string type;
|
||||
std::string contents;
|
||||
msg_.peekType(type, contents);
|
||||
return contents;
|
||||
}
|
||||
|
||||
@@ -80,7 +84,7 @@ int UnixFd::checkedDup(int fd)
|
||||
return fd;
|
||||
}
|
||||
|
||||
const int ret = ::dup(fd); // NOLINT(android-cloexec-dup) // TODO: verify
|
||||
int ret = ::dup(fd); // NOLINT(android-cloexec-dup) // TODO: verify
|
||||
if (ret < 0)
|
||||
{
|
||||
throw std::system_error(errno, std::generic_category(), "dup failed");
|
||||
|
||||
+14
-18
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Utils.h
|
||||
*
|
||||
@@ -30,20 +30,18 @@
|
||||
#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) \
|
||||
#define SDBUS_CHECK_OBJECT_PATH(_PATH) \
|
||||
SDBUS_THROW_ERROR_IF(!sd_bus_object_path_is_valid(_PATH.c_str()), "Invalid object path '" + _PATH + "' provided", EINVAL) \
|
||||
/**/
|
||||
#define SDBUS_CHECK_INTERFACE_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(!sd_bus_interface_name_is_valid(_NAME), std::string("Invalid interface name '") + _NAME + "' provided", EINVAL) \
|
||||
#define SDBUS_CHECK_INTERFACE_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(!sd_bus_interface_name_is_valid(_NAME.c_str()), "Invalid interface name '" + _NAME + "' provided", EINVAL) \
|
||||
/**/
|
||||
#define SDBUS_CHECK_SERVICE_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(*_NAME && !sd_bus_service_name_is_valid(_NAME), std::string("Invalid service name '") + _NAME + "' provided", EINVAL) \
|
||||
#define SDBUS_CHECK_SERVICE_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(!_NAME.empty() && !sd_bus_service_name_is_valid(_NAME.c_str()), "Invalid service name '" + _NAME + "' provided", EINVAL) \
|
||||
/**/
|
||||
#define SDBUS_CHECK_MEMBER_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(!sd_bus_member_name_is_valid(_NAME), std::string("Invalid member name '") + _NAME + "' provided", EINVAL) \
|
||||
#define SDBUS_CHECK_MEMBER_NAME(_NAME) \
|
||||
SDBUS_THROW_ERROR_IF(!sd_bus_member_name_is_valid(_NAME.c_str()), "Invalid member name '" + _NAME + "' provided", EINVAL) \
|
||||
/**/
|
||||
#else
|
||||
#define SDBUS_CHECK_OBJECT_PATH(_PATH)
|
||||
@@ -52,12 +50,10 @@
|
||||
#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
|
||||
{
|
||||
@@ -70,12 +66,12 @@ namespace sdbus::internal {
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME.c_str(), e.what());
|
||||
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME, e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME.c_str(), "Unknown error occurred");
|
||||
sd_bus_error_set(retError, SDBUSCPP_ERROR_NAME, "Unknown error occurred");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,6 +93,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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableUtils.h
|
||||
*
|
||||
|
||||
+32
-34
@@ -2,12 +2,12 @@
|
||||
# DOWNLOAD AND BUILD OF GOOGLETEST
|
||||
#-------------------------------
|
||||
|
||||
find_package(GTest ${SDBUSCPP_GOOGLETEST_VERSION} CONFIG)
|
||||
find_package(GTest ${GOOGLETEST_VERSION} CONFIG)
|
||||
if (NOT TARGET GTest::gmock)
|
||||
# Try pkg-config if GTest was not found through CMake config
|
||||
find_package(PkgConfig)
|
||||
if (PkgConfig_FOUND)
|
||||
pkg_check_modules(GMock IMPORTED_TARGET GLOBAL gmock>=${SDBUSCPP_GOOGLETEST_VERSION})
|
||||
pkg_check_modules(GMock IMPORTED_TARGET GLOBAL gmock>=${GOOGLETEST_VERSION})
|
||||
if(TARGET PkgConfig::GMock)
|
||||
add_library(GTest::gmock ALIAS PkgConfig::GMock)
|
||||
endif()
|
||||
@@ -16,15 +16,15 @@ if (NOT TARGET GTest::gmock)
|
||||
if (NOT TARGET GTest::gmock)
|
||||
include(FetchContent)
|
||||
|
||||
if (SDBUSCPP_GOOGLETEST_VERSION VERSION_GREATER_EQUAL 1.13.0)
|
||||
set(GOOGLETEST_TAG "v${SDBUSCPP_GOOGLETEST_VERSION}")
|
||||
if (GOOGLETEST_VERSION VERSION_GREATER_EQUAL 1.13.0)
|
||||
set(GOOGLETEST_TAG "v${GOOGLETEST_VERSION}")
|
||||
else()
|
||||
set(GOOGLETEST_TAG "release-${SDBUSCPP_GOOGLETEST_VERSION}")
|
||||
set(GOOGLETEST_TAG "release-${GOOGLETEST_VERSION}")
|
||||
endif()
|
||||
|
||||
message("Manually fetching & building googletest ${GOOGLETEST_TAG}...")
|
||||
message("Manually fetching & building googletest v${GOOGLETEST_VERSION}...")
|
||||
FetchContent_Declare(googletest
|
||||
GIT_REPOSITORY ${SDBUSCPP_GOOGLETEST_GIT_REPO}
|
||||
GIT_REPOSITORY ${GOOGLETEST_GIT_REPO}
|
||||
GIT_TAG ${GOOGLETEST_TAG}
|
||||
GIT_SHALLOW 1
|
||||
UPDATE_COMMAND "")
|
||||
@@ -54,46 +54,48 @@ 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_GENERATED_DIR}/integrationtests-adaptor.h
|
||||
${INTEGRATIONTESTS_GENERATED_DIR}/integrationtests-proxy.h)
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp)
|
||||
|
||||
set(PERFTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/perftests)
|
||||
set(PERFTESTS_GENERATED_DIR ${PERFTESTS_SOURCE_DIR}/dbus-api/gen-cpp)
|
||||
set(PERFTESTS_CLIENT_SRCS
|
||||
set(STRESSTESTS_CLIENT_SRCS
|
||||
${PERFTESTS_SOURCE_DIR}/client.cpp
|
||||
${PERFTESTS_GENERATED_DIR}/perftests-proxy.h)
|
||||
set(PERFTESTS_SERVER_SRCS
|
||||
${PERFTESTS_SOURCE_DIR}/perftests-proxy.h)
|
||||
set(STRESSTESTS_SERVER_SRCS
|
||||
${PERFTESTS_SOURCE_DIR}/server.cpp
|
||||
${PERFTESTS_GENERATED_DIR}/perftests-adaptor.h)
|
||||
${PERFTESTS_SOURCE_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_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)
|
||||
${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})
|
||||
|
||||
#----------------------------------
|
||||
# BUILD INFORMATION
|
||||
@@ -102,16 +104,15 @@ set(STRESSTESTS_SRCS
|
||||
add_executable(sdbus-c++-unit-tests ${UNITTESTS_SRCS})
|
||||
target_compile_definitions(sdbus-c++-unit-tests PRIVATE
|
||||
LIBSYSTEMD_VERSION=${SDBUSCPP_LIBSYSTEMD_VERSION}
|
||||
SDBUS_${SDBUS_IMPL}
|
||||
SDBUS_HEADER=<${SDBUS_IMPL}/sd-bus.h>)
|
||||
SDBUS_${LIBSYSTEMD_IMPL}
|
||||
SDBUS_HEADER=<${LIBSYSTEMD_IMPL}/sd-bus.h>)
|
||||
target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib GTest::gmock)
|
||||
|
||||
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")
|
||||
SDBUS_${LIBSYSTEMD})
|
||||
if(NOT LIBSYSTEMD 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)
|
||||
else()
|
||||
@@ -125,18 +126,15 @@ 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 ${PERFTESTS_CLIENT_SRCS})
|
||||
target_include_directories(sdbus-c++-perf-tests-client SYSTEM PRIVATE ${PERFTESTS_GENERATED_DIR})
|
||||
add_executable(sdbus-c++-perf-tests-client ${STRESSTESTS_CLIENT_SRCS})
|
||||
target_link_libraries(sdbus-c++-perf-tests-client sdbus-c++ Threads::Threads)
|
||||
add_executable(sdbus-c++-perf-tests-server ${PERFTESTS_SERVER_SRCS})
|
||||
target_include_directories(sdbus-c++-perf-tests-server SYSTEM PRIVATE ${PERFTESTS_GENERATED_DIR})
|
||||
add_executable(sdbus-c++-perf-tests-server ${STRESSTESTS_SERVER_SRCS})
|
||||
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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusAsyncMethodsTests.cpp
|
||||
*
|
||||
@@ -25,30 +25,27 @@
|
||||
*/
|
||||
|
||||
#include "TestFixture.h"
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "Defs.h"
|
||||
#include <sdbus-c++/sdbus-c++.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 <utility>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -90,27 +87,27 @@ TYPED_TEST(AsyncSdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTime
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchronousMethodAsynchronously)
|
||||
TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
|
||||
{
|
||||
// Yeah, this is kinda timing-dependent test, but times should be safe...
|
||||
std::mutex mtx;
|
||||
std::vector<uint32_t> results;
|
||||
std::atomic invoke{false};
|
||||
std::atomic startedCount{0};
|
||||
std::atomic<bool> invoke{};
|
||||
std::atomic<int> startedCount{};
|
||||
auto call = [&](uint32_t param)
|
||||
{
|
||||
TestProxy proxy{SERVICE_NAME, OBJECT_PATH};
|
||||
TestProxy proxy{BUS_NAME, OBJECT_PATH};
|
||||
++startedCount;
|
||||
while (!invoke) ;
|
||||
auto result = proxy.doOperationAsync(param);
|
||||
std::lock_guard const guard(mtx);
|
||||
std::lock_guard<std::mutex> 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& thread){ thread.join(); });
|
||||
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
|
||||
|
||||
ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
|
||||
}
|
||||
@@ -118,11 +115,11 @@ TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchronousMethodAsynchronously)
|
||||
TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
|
||||
{
|
||||
std::atomic<size_t> resultCount{};
|
||||
std::atomic invoke{false};
|
||||
std::atomic startedCount{0};
|
||||
std::atomic<bool> invoke{};
|
||||
std::atomic<int> startedCount{};
|
||||
auto call = [&]()
|
||||
{
|
||||
TestProxy proxy{SERVICE_NAME, OBJECT_PATH};
|
||||
TestProxy proxy{BUS_NAME, OBJECT_PATH};
|
||||
++startedCount;
|
||||
while (!invoke) ;
|
||||
|
||||
@@ -140,24 +137,11 @@ 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& thread){ thread.join(); });
|
||||
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
|
||||
|
||||
ASSERT_THAT(resultCount, Eq(1500));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchronousMethodWithLargeMessage)
|
||||
{
|
||||
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));
|
||||
|
||||
auto result1 = this->m_proxy->doOperationAsyncWithLargeData(0, largeMap); // Sends large map back in the context of the callback (event loop thread)
|
||||
auto result2 = this->m_proxy->doOperationAsyncWithLargeData(500, largeMap); // Sends large map back outside the context of the event loop thread
|
||||
|
||||
ASSERT_THAT(result1, Eq(largeMap));
|
||||
ASSERT_THAT(result2, Eq(largeMap));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
@@ -193,20 +177,9 @@ TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutu
|
||||
ASSERT_THAT(returnValue, Eq(100));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, InvokesMethodWithLargeDataAsynchronouslyOnClientSideWithFuture)
|
||||
{
|
||||
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));
|
||||
|
||||
auto future = this->m_proxy->doOperationWithLargeDataClientSideAsync(largeMap, sdbus::with_future);
|
||||
|
||||
ASSERT_THAT(future.get(), Eq(largeMap));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
|
||||
{
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){});
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){});
|
||||
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
@@ -217,7 +190,7 @@ TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
call.cancel();
|
||||
@@ -225,24 +198,11 @@ TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide)
|
||||
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSideByDestroyingOwningSlot)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
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);
|
||||
// Now the slot is destroyed, cancelling the async call
|
||||
}
|
||||
|
||||
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, std::optional<sdbus::Error> /*err*/){ promise.set_value(1); });
|
||||
auto call = this->m_proxy->doOperationClientSideAsync(100);
|
||||
|
||||
call.cancel();
|
||||
@@ -254,7 +214,7 @@ TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenC
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const std::optional<sdbus::Error>& /*err*/){ promise.set_value(1); });
|
||||
this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, 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
|
||||
@@ -264,7 +224,7 @@ TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenC
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending)
|
||||
{
|
||||
sdbus::PendingAsyncCall const call;
|
||||
sdbus::PendingAsyncCall call;
|
||||
|
||||
ASSERT_FALSE(call.isPending());
|
||||
}
|
||||
@@ -278,7 +238,7 @@ TYPED_TEST(AsyncSdbusTestObject, SupportsAsyncCallCopyAssignment)
|
||||
ASSERT_TRUE(call.isPending());
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncSdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails) // NOLINT(readability-function-cognitive-complexity)
|
||||
TYPED_TEST(AsyncSdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
/**
|
||||
* (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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusConnectionTests.cpp
|
||||
*
|
||||
@@ -33,10 +33,13 @@
|
||||
|
||||
// gmock
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
// STL
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using ::testing::Eq;
|
||||
using namespace sdbus::test;
|
||||
|
||||
/*-------------------------------------*/
|
||||
@@ -48,43 +51,38 @@ TEST(Connection, CanBeDefaultConstructed)
|
||||
ASSERT_NO_THROW(auto con = sdbus::createBusConnection());
|
||||
}
|
||||
|
||||
TEST(Connection, CanRequestName)
|
||||
TEST(Connection, CanRequestRegisteredDbusName)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
|
||||
// In case of system bus connection, requesting may throw as we need to allow that first through a config file in /etc/dbus-1/system.d
|
||||
ASSERT_NO_THROW(connection->requestName(SERVICE_NAME))
|
||||
ASSERT_NO_THROW(connection->requestName(BUS_NAME))
|
||||
<< "Perhaps you've forgotten to copy `org.sdbuscpp.integrationtests.conf` file to `/etc/dbus-1/system.d` directory before running the tests?";
|
||||
}
|
||||
|
||||
TEST(SystemBusConnection, CannotRequestNonregisteredDbusName)
|
||||
{
|
||||
auto connection = sdbus::createSystemBusConnection();
|
||||
sdbus::ServiceName const notSupportedBusName{"some.random.not.supported.dbus.name"};
|
||||
|
||||
ASSERT_THROW(connection->requestName(notSupportedBusName), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(Connection, CanReleaseRequestedName)
|
||||
TEST(Connection, CannotRequestNonregisteredDbusName)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
connection->requestName(SERVICE_NAME);
|
||||
ASSERT_THROW(connection->requestName("some.random.not.supported.dbus.name"), sdbus::Error);
|
||||
}
|
||||
|
||||
ASSERT_NO_THROW(connection->releaseName(SERVICE_NAME));
|
||||
TEST(Connection, CanReleasedRequestedName)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
|
||||
connection->requestName(BUS_NAME);
|
||||
ASSERT_NO_THROW(connection->releaseName(BUS_NAME));
|
||||
}
|
||||
|
||||
TEST(Connection, CannotReleaseNonrequestedName)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
sdbus::ServiceName const notAcquiredBusName{"some.random.unacquired.name"};
|
||||
|
||||
ASSERT_THROW(connection->releaseName(notAcquiredBusName), sdbus::Error);
|
||||
ASSERT_THROW(connection->releaseName("some.random.nonrequested.name"), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(Connection, CanEnterAndLeaveInternalEventLoop)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
connection->requestName(SERVICE_NAME);
|
||||
connection->requestName(BUS_NAME);
|
||||
|
||||
std::thread t([&](){ connection->enterEventLoop(); });
|
||||
connection->leaveEventLoop();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusGeneralTests.cpp
|
||||
*
|
||||
@@ -27,22 +27,23 @@
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "TestFixture.h"
|
||||
#include "Defs.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include "sdbus-c++/sdbus-c++.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <unistd.h>
|
||||
#include <variant>
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace sdbus::test;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
using ADirectConnection = TestFixtureWithDirectConnection;
|
||||
|
||||
@@ -50,38 +51,36 @@ using ADirectConnection = TestFixtureWithDirectConnection;
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TEST(AdaptorAndProxy, CanBeConstructedSuccessfully)
|
||||
TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
|
||||
{
|
||||
auto connection = sdbus::createBusConnection();
|
||||
connection->requestName(SERVICE_NAME);
|
||||
connection->requestName(BUS_NAME);
|
||||
|
||||
ASSERT_NO_THROW(const TestAdaptor adaptor(*connection, OBJECT_PATH));
|
||||
ASSERT_NO_THROW(const TestProxy proxy(SERVICE_NAME, OBJECT_PATH));
|
||||
|
||||
connection->releaseName(SERVICE_NAME);
|
||||
ASSERT_NO_THROW(TestAdaptor adaptor(*connection, OBJECT_PATH));
|
||||
ASSERT_NO_THROW(TestProxy proxy(BUS_NAME, OBJECT_PATH));
|
||||
}
|
||||
|
||||
TEST(AProxy, DoesNotSupportMoveSemantics)
|
||||
TEST(AProxy, SupportsMoveSemantics)
|
||||
{
|
||||
static_assert(!std::is_move_constructible_v<DummyTestProxy>);
|
||||
static_assert(!std::is_move_assignable_v<DummyTestProxy>);
|
||||
static_assert(std::is_move_constructible_v<DummyTestProxy>);
|
||||
static_assert(std::is_move_assignable_v<DummyTestProxy>);
|
||||
}
|
||||
|
||||
TEST(AnAdaptor, DoesNotSupportMoveSemantics)
|
||||
TEST(AnAdaptor, SupportsMoveSemantics)
|
||||
{
|
||||
static_assert(!std::is_move_constructible_v<DummyTestAdaptor>);
|
||||
static_assert(!std::is_move_assignable_v<DummyTestAdaptor>);
|
||||
static_assert(std::is_move_constructible_v<DummyTestAdaptor>);
|
||||
static_assert(std::is_move_assignable_v<DummyTestAdaptor>);
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
|
||||
{
|
||||
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](const sdbus::Message& msg)
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
}, sdbus::return_slot);
|
||||
});
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
@@ -90,20 +89,19 @@ TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRu
|
||||
|
||||
TYPED_TEST(AConnection, CanInstallMatchRuleAsynchronously)
|
||||
{
|
||||
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic matchingMessageReceived{false};
|
||||
std::atomic matchRuleInstalled{false};
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
std::atomic<bool> matchRuleInstalled{false};
|
||||
auto slot = this->s_proxyConnection->addMatchAsync( matchRule
|
||||
, [&](const sdbus::Message& msg)
|
||||
, [&](sdbus::Message msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
}
|
||||
, [&](const sdbus::Message& /*msg*/)
|
||||
, [&](sdbus::Message /*msg*/)
|
||||
{
|
||||
matchRuleInstalled = true;
|
||||
}
|
||||
, sdbus::return_slot );
|
||||
} );
|
||||
|
||||
EXPECT_TRUE(waitUntil(matchRuleInstalled));
|
||||
|
||||
@@ -114,13 +112,13 @@ TYPED_TEST(AConnection, CanInstallMatchRuleAsynchronously)
|
||||
|
||||
TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot)
|
||||
{
|
||||
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](const sdbus::Message& msg)
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
}, sdbus::return_slot);
|
||||
});
|
||||
slot.reset();
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
@@ -130,16 +128,16 @@ TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedS
|
||||
|
||||
TYPED_TEST(AConnection, CanAddFloatingMatchRule)
|
||||
{
|
||||
auto matchRule = "sender='" + SERVICE_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic matchingMessageReceived{false};
|
||||
auto con = sdbus::createBusConnection();
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
std::atomic<bool> matchingMessageReceived{false};
|
||||
auto con = sdbus::createSystemBusConnection();
|
||||
con->enterEventLoopAsync();
|
||||
auto callback = [&](const sdbus::Message& msg)
|
||||
auto callback = [&](sdbus::Message msg)
|
||||
{
|
||||
if(msg.getPath() == OBJECT_PATH)
|
||||
matchingMessageReceived = true;
|
||||
};
|
||||
con->addMatch(matchRule, std::move(callback));
|
||||
con->addMatch(matchRule, std::move(callback), sdbus::floating_slot);
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
[[maybe_unused]] auto gotMessage = waitUntil(matchingMessageReceived, 2s);
|
||||
assert(gotMessage);
|
||||
@@ -155,11 +153,11 @@ 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, [&](const sdbus::Message& msg)
|
||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
|
||||
{
|
||||
if(msg.getMemberName() == "simpleSignal"sv)
|
||||
if(msg.getMemberName() == "simpleSignal")
|
||||
numberOfMatchingMessages++;
|
||||
}, sdbus::return_slot);
|
||||
});
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
|
||||
this->m_adaptor->emitSignalWithMap({});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusMethodsTests.cpp
|
||||
*
|
||||
@@ -25,52 +25,41 @@
|
||||
*/
|
||||
|
||||
#include "TestFixture.h"
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "Defs.h"
|
||||
#include <sdbus-c++/sdbus-c++.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 <vector>
|
||||
#include <variant>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
using namespace sdbus::test;
|
||||
|
||||
namespace my {
|
||||
struct Struct
|
||||
{
|
||||
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); // NOLINT(readability-identifier-length)
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsEmptyMethodSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsEmptyMethodSuccesfully)
|
||||
{
|
||||
ASSERT_NO_THROW(this->m_proxy->noArgNoReturn());
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithBaseTypesSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully)
|
||||
{
|
||||
auto resInt = this->m_proxy->getInt();
|
||||
ASSERT_THAT(resInt, Eq(INT32_VALUE));
|
||||
@@ -79,92 +68,85 @@ TYPED_TEST(SdbusTestObject, CallsMethodsWithBaseTypesSuccessfully)
|
||||
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithTuplesSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithTuplesSuccesfully)
|
||||
{
|
||||
auto resTuple = this->m_proxy->getTuple();
|
||||
ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE));
|
||||
ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccesfully)
|
||||
{
|
||||
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> const strctA{};
|
||||
auto vectorRes = this->m_proxy->getInts16FromStruct(strctA);
|
||||
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
|
||||
auto vectorRes = this->m_proxy->getInts16FromStruct(a);
|
||||
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>> const strctB{
|
||||
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
|
||||
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE}
|
||||
};
|
||||
vectorRes = this->m_proxy->getInts16FromStruct(strctB);
|
||||
vectorRes = this->m_proxy->getInts16FromStruct(b);
|
||||
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccesfully)
|
||||
{
|
||||
sdbus::Variant const var{DOUBLE_VALUE};
|
||||
sdbus::Variant const variantRes = this->m_proxy->processVariant(var);
|
||||
sdbus::Variant v{DOUBLE_VALUE};
|
||||
sdbus::Variant variantRes = this->m_proxy->processVariant(v);
|
||||
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStdVariantSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
|
||||
{
|
||||
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 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}}};
|
||||
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);
|
||||
decltype(mapOfVariants) res{ {sdbus::Variant{-2}, sdbus::Variant{false}}
|
||||
, {sdbus::Variant{0}, sdbus::Variant{false}}
|
||||
, {sdbus::Variant{2}, sdbus::Variant{true}}};
|
||||
|
||||
ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>()));
|
||||
ASSERT_THAT(mapOfVariants[0].get<bool>(), Eq(res[0].get<bool>()));
|
||||
ASSERT_THAT(mapOfVariants[2].get<bool>(), Eq(res[2].get<bool>()));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStructInStructSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithStructInStructSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->getStructInStruct();
|
||||
ASSERT_THAT(val.template get<0>(), Eq(STRING_VALUE));
|
||||
ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoStructsSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->sumStructItems({1, 2}, {3, 4});
|
||||
ASSERT_THAT(val, Eq(1 + 2 + 3 + 4));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoVectorsSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
|
||||
{
|
||||
auto val = this->m_proxy->sumArrayItems({1, 7}, {2, 3, 4});
|
||||
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3 + 4));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithSignatureSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
|
||||
{
|
||||
auto resSignature = this->m_proxy->getSignature();
|
||||
ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithObjectPathSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithObjectPathSuccesfully)
|
||||
{
|
||||
auto resObjectPath = this->m_proxy->getObjPath();
|
||||
ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithUnixFdSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithUnixFdSuccesfully)
|
||||
{
|
||||
auto resUnixFd = this->m_proxy->getUnixFd();
|
||||
ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithComplexTypeSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
|
||||
{
|
||||
auto resComplex = this->m_proxy->getComplex();
|
||||
ASSERT_THAT(resComplex.count(0), Eq(1));
|
||||
@@ -242,13 +224,13 @@ TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentInterface)
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
|
||||
{
|
||||
TestProxy proxy(sdbus::ServiceName{"sdbuscpp.destination.that.does.not.exist"}, OBJECT_PATH);
|
||||
TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
|
||||
ASSERT_THROW(proxy.getInt(), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
|
||||
{
|
||||
TestProxy proxy(SERVICE_NAME, sdbus::ObjectPath{"/sdbuscpp/path/that/does/not/exist"});
|
||||
TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist");
|
||||
ASSERT_THROW(proxy.getInt(), sdbus::Error);
|
||||
}
|
||||
|
||||
@@ -260,35 +242,12 @@ TYPED_TEST(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
|
||||
EXPECT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanSendAndReceiveDictionariesAsCustomStructsImplicitly)
|
||||
{
|
||||
// This test demonstrates that sdbus-c++ can send a SDBUSCPP_REGISTER_STRUCT-described struct as a dictionary of strings to variants,
|
||||
// and that sdbus-c++ can automatically deserialize a dictionary of strings to variants into such a struct (instead of a map).
|
||||
const my::Struct structSent{3545342, "hello"s, {3.14, 2.4568546}};
|
||||
my::Struct structReceived;
|
||||
|
||||
this->m_proxy->getProxy().callMethod("returnDictionary")
|
||||
.onInterface("org.sdbuscpp.integrationtests")
|
||||
.withArguments(sdbus::as_dictionary(structSent))
|
||||
.storeResultsTo(structReceived);
|
||||
|
||||
ASSERT_THAT(structReceived, Eq(structSent));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInMethodCallHandler)
|
||||
{
|
||||
this->m_proxy->doOperation(10); // This will save pointer to method call message on server side
|
||||
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_methodName, Eq("doOperation"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ProvidesSerialInMethodCallAndMethodReplyMessage)
|
||||
{
|
||||
auto reply = this->m_proxy->doOperationOnBasicAPILevel(ANY_UNSIGNED_NUMBER);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->m_methodCallMsg->getCookie(), Gt(0));
|
||||
ASSERT_THAT(reply.getReplyCookie(), Eq(this->m_proxy->m_methodCallMsg->getCookie())); // Pairing method reply with method call message
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperation"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCallHandler)
|
||||
@@ -296,31 +255,7 @@ TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCal
|
||||
this->m_proxy->doOperationAsync(10); // This will save pointer to method call message on server side
|
||||
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_methodName, Eq("doOperationAsync"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CallsMethodWithLargeArgument)
|
||||
{
|
||||
std::map<int, std::string> collection;
|
||||
//std::size_t totalSize{};
|
||||
for (int i = 0; i < 400'000; i++)
|
||||
{
|
||||
collection[i] = ("This is a string of fifty characters. This is a string of fifty " + std::to_string(i));
|
||||
//totalSize += sizeof(int) + collection[i].size();
|
||||
}
|
||||
//printf("Sending large message with collection of size %zu bytes\n", totalSize);
|
||||
this->m_proxy->sendLargeMessage(collection);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanSendCallsAndReceiveRepliesWithLargeData)
|
||||
{
|
||||
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));
|
||||
|
||||
auto returnedMap = this->m_proxy->doOperationWithLargeData(largeMap);
|
||||
|
||||
ASSERT_THAT(returnedMap, Eq(largeMap));
|
||||
ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperationAsync"));
|
||||
}
|
||||
|
||||
#if LIBSYSTEMD_VERSION>=240
|
||||
@@ -339,7 +274,7 @@ TYPED_TEST(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLe
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
{
|
||||
auto proxy = std::make_unique<TestProxy>(SERVICE_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
auto proxy = std::make_unique<TestProxy>(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
|
||||
auto multiplyRes = proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
|
||||
|
||||
@@ -349,16 +284,15 @@ TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
|
||||
{
|
||||
auto& object = this->m_adaptor->getObject();
|
||||
sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"};
|
||||
auto vtableSlot = object.addVTable( interfaceName
|
||||
, { 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; }) }
|
||||
auto vtableSlot = object.addVTable( "org.sdbuscpp.integrationtests2"
|
||||
, { 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 );
|
||||
|
||||
// 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);
|
||||
auto proxy = sdbus::createProxy(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
int result{};
|
||||
proxy->callMethod("subtract").onInterface(interfaceName).withArguments(10, 2).storeResultsTo(result);
|
||||
proxy->callMethod("subtract").onInterface("org.sdbuscpp.integrationtests2").withArguments(10, 2).storeResultsTo(result);
|
||||
|
||||
ASSERT_THAT(result, Eq(8));
|
||||
}
|
||||
@@ -366,15 +300,14 @@ TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
|
||||
TYPED_TEST(SdbusTestObject, CanUnregisterAdditionallyRegisteredVTableAtAnyTime)
|
||||
{
|
||||
auto& object = this->m_adaptor->getObject();
|
||||
sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"};
|
||||
|
||||
auto vtableSlot = object.addVTable( interfaceName
|
||||
, { 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; }) }
|
||||
auto vtableSlot = object.addVTable( "org.sdbuscpp.integrationtests2"
|
||||
, { 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...
|
||||
auto proxy = sdbus::createLightWeightProxy(SERVICE_NAME, OBJECT_PATH);
|
||||
ASSERT_THROW(proxy->callMethod("subtract").onInterface(interfaceName).withArguments(10, 2), sdbus::Error);
|
||||
auto proxy = sdbus::createProxy(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
ASSERT_THROW(proxy->callMethod("subtract").onInterface("org.sdbuscpp.integrationtests2").withArguments(10, 2), sdbus::Error);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusPropertiesTests.cpp
|
||||
*
|
||||
@@ -25,15 +25,26 @@
|
||||
*/
|
||||
|
||||
#include "TestFixture.h"
|
||||
#include "Defs.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.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;
|
||||
@@ -44,7 +55,7 @@ using namespace sdbus::test;
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ReadsReadOnlyPropertySuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
|
||||
{
|
||||
ASSERT_THAT(this->m_proxy->state(), Eq(DEFAULT_STATE_VALUE));
|
||||
}
|
||||
@@ -54,9 +65,9 @@ TYPED_TEST(SdbusTestObject, FailsWritingToReadOnlyProperty)
|
||||
ASSERT_THROW(this->m_proxy->setStateProperty("new_value"), sdbus::Error);
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWritePropertySuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
|
||||
{
|
||||
uint32_t const newActionValue = 5678;
|
||||
uint32_t newActionValue = 5678;
|
||||
|
||||
this->m_proxy->action(newActionValue);
|
||||
|
||||
@@ -70,12 +81,3 @@ TYPED_TEST(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHa
|
||||
ASSERT_THAT(this->m_adaptor->m_propertySetMsg, NotNull());
|
||||
ASSERT_THAT(this->m_adaptor->m_propertySetSender, Not(IsEmpty()));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, WritesAndReadsReadWriteVariantPropertySuccessfully)
|
||||
{
|
||||
sdbus::Variant const newActionValue{5678};
|
||||
|
||||
this->m_proxy->actionVariant(newActionValue);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->actionVariant().template get<int>(), Eq(5678));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file AdaptorAndProxy_test.cpp
|
||||
*
|
||||
@@ -27,17 +27,19 @@
|
||||
#include "TestFixture.h"
|
||||
#include "TestAdaptor.h"
|
||||
#include "TestProxy.h"
|
||||
#include "Defs.h"
|
||||
#include <sdbus-c++/sdbus-c++.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;
|
||||
@@ -46,17 +48,17 @@ using namespace sdbus::test;
|
||||
/* -- TEST CASES -- */
|
||||
/*-------------------------------------*/
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSimpleSignal));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
|
||||
{
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, SERVICE_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, SERVICE_NAME, OBJECT_PATH);
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
this->m_adaptor->emitSimpleSignal();
|
||||
|
||||
@@ -67,7 +69,7 @@ TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccessfully)
|
||||
|
||||
TYPED_TEST(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
|
||||
{
|
||||
sdbus::ServiceName const otherBusName{SERVICE_NAME + "2"};
|
||||
auto otherBusName = BUS_NAME + "2";
|
||||
auto connection2 = sdbus::createBusConnection(otherBusName);
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*connection2, OBJECT_PATH);
|
||||
|
||||
@@ -76,7 +78,7 @@ TYPED_TEST(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
|
||||
ASSERT_FALSE(waitUntil(this->m_proxy->m_gotSimpleSignal, 1s));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithMapSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithMapSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
|
||||
|
||||
@@ -85,33 +87,33 @@ TYPED_TEST(SdbusTestObject, EmitsSignalWithMapSuccessfully)
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("one"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithLargeMapSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully)
|
||||
{
|
||||
std::map<int32_t, std::string> largeMap;
|
||||
for (int32_t i = 0; i < 20'000; ++i)
|
||||
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1));
|
||||
this->m_adaptor->emitSignalWithMap(largeMap);
|
||||
std::map<int32_t, std::string> largeMap;
|
||||
for (int32_t i = 0; i < 20'000; ++i)
|
||||
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1));
|
||||
this->m_adaptor->emitSignalWithMap(largeMap);
|
||||
|
||||
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1"));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2"));
|
||||
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1"));
|
||||
ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithVariantSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
|
||||
{
|
||||
double const val = 3.14;
|
||||
this->m_adaptor->emitSignalWithVariant(sdbus::Variant{val});
|
||||
double d = 3.14;
|
||||
this->m_adaptor->emitSignalWithVariant(sdbus::Variant{d});
|
||||
|
||||
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithVariant));
|
||||
ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(val));
|
||||
ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(d));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccessfully)
|
||||
TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
|
||||
{
|
||||
this->m_adaptor->emitSignalWithoutRegistration({"platform", sdbus::Signature{"av"}});
|
||||
this->m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}});
|
||||
|
||||
ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithSignature));
|
||||
ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq(sdbus::Signature{"av"}));
|
||||
ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq("av"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
|
||||
@@ -121,7 +123,7 @@ TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
|
||||
waitUntil(this->m_proxy->m_gotSimpleSignal);
|
||||
|
||||
ASSERT_THAT(this->m_proxy->m_signalMsg, NotNull());
|
||||
ASSERT_THAT(this->m_proxy->m_signalName, Eq(std::string("simpleSignal")));
|
||||
ASSERT_THAT(this->m_proxy->m_signalMemberName, Eq("simpleSignal"));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, UnregistersSignalHandler)
|
||||
@@ -135,8 +137,8 @@ TYPED_TEST(SdbusTestObject, UnregistersSignalHandler)
|
||||
|
||||
TYPED_TEST(SdbusTestObject, UnregistersSignalHandlerForSomeProxies)
|
||||
{
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, SERVICE_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, SERVICE_NAME, OBJECT_PATH);
|
||||
auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler());
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file DBusStandardInterfacesTests.cpp
|
||||
*
|
||||
@@ -26,25 +26,24 @@
|
||||
|
||||
#include "TestFixture.h"
|
||||
#include "TestAdaptor.h"
|
||||
#include "Defs.h"
|
||||
#include "integrationtests-adaptor.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include "TestProxy.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;
|
||||
@@ -83,7 +82,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, const sdbus::Variant& value)
|
||||
this->m_proxy->GetAsync(INTERFACE_NAME, "state", [&](std::optional<sdbus::Error> err, sdbus::Variant value)
|
||||
{
|
||||
if (!err)
|
||||
promise.set_value(value.get<std::string>());
|
||||
@@ -103,7 +102,7 @@ TYPED_TEST(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterfaceWith
|
||||
|
||||
TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
|
||||
{
|
||||
uint32_t const newActionValue = 2345;
|
||||
uint32_t newActionValue = 2345;
|
||||
|
||||
this->m_proxy->Set(INTERFACE_NAME, "action", sdbus::Variant{newActionValue});
|
||||
|
||||
@@ -112,7 +111,7 @@ TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
|
||||
|
||||
TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface)
|
||||
{
|
||||
uint32_t const newActionValue = 2346;
|
||||
uint32_t newActionValue = 2346;
|
||||
std::promise<void> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
@@ -128,29 +127,9 @@ TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface)
|
||||
ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CancelsAsynchronousPropertySettingViaPropertiesInterface)
|
||||
{
|
||||
uint32_t const newActionValue = 2346;
|
||||
std::promise<void> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
{
|
||||
auto slot = this->m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, [&](std::optional<sdbus::Error> err)
|
||||
{
|
||||
if (!err)
|
||||
promise.set_value();
|
||||
else
|
||||
promise.set_exception(std::make_exception_ptr(*std::move(err)));
|
||||
}, sdbus::return_slot);
|
||||
// Now the slot is destroyed, cancelling the async call
|
||||
}
|
||||
|
||||
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture)
|
||||
{
|
||||
uint32_t const newActionValue = 2347;
|
||||
uint32_t newActionValue = 2347;
|
||||
|
||||
auto future = this->m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, sdbus::with_future);
|
||||
|
||||
@@ -162,19 +141,18 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
|
||||
{
|
||||
const auto properties = this->m_proxy->GetAll(INTERFACE_NAME);
|
||||
|
||||
ASSERT_THAT(properties, SizeIs(4));
|
||||
EXPECT_THAT(properties.at(STATE_PROPERTY).template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_PROPERTY).template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get<sdbus::Variant>().template get<std::string>(), Eq(DEFAULT_ACTION_VARIANT_VALUE));
|
||||
EXPECT_THAT(properties.at(BLOCKING_PROPERTY).template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
ASSERT_THAT(properties, SizeIs(3));
|
||||
EXPECT_THAT(properties.at("state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at("blocking").template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterface)
|
||||
{
|
||||
std::promise<std::map<sdbus::PropertyName, sdbus::Variant>> promise;
|
||||
std::promise<std::map<std::string, sdbus::Variant>> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
this->m_proxy->GetAllAsync(INTERFACE_NAME, [&](std::optional<sdbus::Error> err, std::map<sdbus::PropertyName, sdbus::Variant> value)
|
||||
this->m_proxy->GetAllAsync(INTERFACE_NAME, [&](std::optional<sdbus::Error> err, std::map<std::string, sdbus::Variant> value)
|
||||
{
|
||||
if (!err)
|
||||
promise.set_value(std::move(value));
|
||||
@@ -183,11 +161,10 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfac
|
||||
});
|
||||
const auto properties = future.get();
|
||||
|
||||
ASSERT_THAT(properties, SizeIs(4));
|
||||
EXPECT_THAT(properties.at(STATE_PROPERTY).get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_PROPERTY).get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get<sdbus::Variant>().template get<std::string>(), Eq(DEFAULT_ACTION_VARIANT_VALUE));
|
||||
EXPECT_THAT(properties.at(BLOCKING_PROPERTY).get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
ASSERT_THAT(properties, SizeIs(3));
|
||||
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfaceWithFuture)
|
||||
@@ -196,43 +173,42 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfac
|
||||
|
||||
auto properties = future.get();
|
||||
|
||||
ASSERT_THAT(properties, SizeIs(4));
|
||||
EXPECT_THAT(properties.at(STATE_PROPERTY).template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_PROPERTY).template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get<sdbus::Variant>().template get<std::string>(), Eq(DEFAULT_ACTION_VARIANT_VALUE));
|
||||
EXPECT_THAT(properties.at(BLOCKING_PROPERTY).template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
ASSERT_THAT(properties, SizeIs(3));
|
||||
EXPECT_THAT(properties.at("state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
|
||||
EXPECT_THAT(properties.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(properties.at("blocking").template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
|
||||
{
|
||||
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*/ )
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& /*invalidatedProperties*/ )
|
||||
{
|
||||
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
|
||||
EXPECT_THAT(changedProperties, SizeIs(1));
|
||||
EXPECT_THAT(changedProperties.at(BLOCKING_PROPERTY).get<bool>(), Eq(!DEFAULT_BLOCKING_VALUE));
|
||||
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(!DEFAULT_BLOCKING_VALUE));
|
||||
signalReceived = true;
|
||||
};
|
||||
|
||||
this->m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
|
||||
this->m_proxy->action(DEFAULT_ACTION_VALUE*2);
|
||||
this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {BLOCKING_PROPERTY});
|
||||
this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"});
|
||||
|
||||
ASSERT_TRUE(waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) // NOLINT(readability-function-cognitive-complexity)
|
||||
TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
|
||||
{
|
||||
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 )
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties )
|
||||
{
|
||||
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
|
||||
EXPECT_THAT(changedProperties, SizeIs(1));
|
||||
EXPECT_THAT(changedProperties.at(BLOCKING_PROPERTY).get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
|
||||
ASSERT_THAT(invalidatedProperties, SizeIs(1));
|
||||
EXPECT_THAT(invalidatedProperties[0], Eq("action"));
|
||||
signalReceived = true;
|
||||
@@ -258,75 +234,35 @@ TYPED_TEST(SdbusTestObject, GetsManagedObjectsSuccessfully)
|
||||
|
||||
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
|
||||
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH)
|
||||
.at(sdbus::InterfaceName{org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME})
|
||||
.at(ACTION_PROPERTY).template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
|
||||
.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2)
|
||||
.at(sdbus::InterfaceName{org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME})
|
||||
.at(ACTION_PROPERTY).template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
|
||||
.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronously)
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
|
||||
{
|
||||
std::promise<size_t> promise;
|
||||
auto future = promise.get_future();
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
ASSERT_THAT(future.get(), Eq(2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronouslyViaSlotReturningOverload)
|
||||
{
|
||||
std::promise<size_t> promise;
|
||||
auto future = promise.get_future();
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
|
||||
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);
|
||||
|
||||
ASSERT_THAT(future.get(), Eq(2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, GetsManagedObjectsAsynchronouslyViaFutureOverload)
|
||||
{
|
||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||
|
||||
auto future = this->m_objectManagerProxy->GetManagedObjectsAsync(sdbus::with_future);
|
||||
|
||||
ASSERT_THAT(future.get().size(), Eq(2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) // NOLINT(readability-function-cognitive-complexity)
|
||||
{
|
||||
std::atomic signalReceived{false};
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>& interfacesAndProperties )
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
EXPECT_THAT(interfacesAndProperties, SizeIs(1));
|
||||
EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1));
|
||||
#if LIBSYSTEMD_VERSION<=244
|
||||
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(4));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY));
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
|
||||
#else
|
||||
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
|
||||
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
|
||||
// So in this specific instance, `action' property is no more added to the list.
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY));
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
|
||||
#endif
|
||||
signalReceived = true;
|
||||
};
|
||||
@@ -336,11 +272,11 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterface
|
||||
ASSERT_TRUE(waitUntil(signalReceived));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) // NOLINT(readability-function-cognitive-complexity)
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
|
||||
{
|
||||
std::atomic signalReceived{false};
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>& interfacesAndProperties )
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
#if LIBSYSTEMD_VERSION<=250
|
||||
@@ -352,19 +288,17 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) //
|
||||
#endif
|
||||
#if LIBSYSTEMD_VERSION<=244
|
||||
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(4));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY));
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
|
||||
#else
|
||||
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
|
||||
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
|
||||
// So in this specific instance, `action' property is no more added to the list.
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY));
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
|
||||
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
|
||||
#endif
|
||||
signalReceived = true;
|
||||
};
|
||||
@@ -376,9 +310,9 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) //
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
|
||||
{
|
||||
std::atomic signalReceived{false};
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<sdbus::InterfaceName>& interfaces )
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
ASSERT_THAT(interfaces, SizeIs(1));
|
||||
@@ -393,9 +327,9 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfa
|
||||
|
||||
TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
|
||||
{
|
||||
std::atomic signalReceived{false};
|
||||
std::atomic<bool> signalReceived{false};
|
||||
this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<sdbus::InterfaceName>& interfaces )
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
#if LIBSYSTEMD_VERSION<=250
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Defs.h
|
||||
*
|
||||
@@ -32,18 +32,14 @@
|
||||
#include <ostream>
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdbus::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
const InterfaceName INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
|
||||
const ServiceName SERVICE_NAME{"org.sdbuscpp.integrationtests"};
|
||||
const ServiceName EMPTY_DESTINATION;
|
||||
const ObjectPath MANAGER_PATH {"/org/sdbuscpp/integrationtests"};
|
||||
const ObjectPath OBJECT_PATH {"/org/sdbuscpp/integrationtests/ObjectA1"};
|
||||
const ObjectPath OBJECT_PATH_2{"/org/sdbuscpp/integrationtests/ObjectB1"};
|
||||
const PropertyName STATE_PROPERTY{"state"};
|
||||
const PropertyName ACTION_PROPERTY{"action"};
|
||||
const PropertyName ACTION_VARIANT_PROPERTY{"actionVariant"};
|
||||
const PropertyName BLOCKING_PROPERTY{"blocking"};
|
||||
const std::string INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
|
||||
const std::string BUS_NAME = INTERFACE_NAME;
|
||||
const std::string EMPTY_DESTINATION;
|
||||
const std::string MANAGER_PATH {"/org/sdbuscpp/integrationtests"};
|
||||
const std::string OBJECT_PATH {"/org/sdbuscpp/integrationtests/ObjectA1"};
|
||||
const std::string OBJECT_PATH_2{"/org/sdbuscpp/integrationtests/ObjectB1"};
|
||||
const std::string DIRECT_CONNECTION_SOCKET_PATH{std::filesystem::temp_directory_path() / "sdbus-cpp-direct-connection-test"};
|
||||
|
||||
constexpr const uint8_t UINT8_VALUE{1};
|
||||
@@ -53,30 +49,28 @@ constexpr const int32_t INT32_VALUE{-42};
|
||||
constexpr const int32_t INT64_VALUE{-1024};
|
||||
|
||||
const std::string STRING_VALUE{"sdbus-c++-testing"};
|
||||
const Signature SIGNATURE_VALUE{"a{is}"};
|
||||
const ObjectPath OBJECT_PATH_VALUE{"/"};
|
||||
const sdbus::Signature SIGNATURE_VALUE{"a{is}"};
|
||||
const sdbus::ObjectPath OBJECT_PATH_VALUE{"/"};
|
||||
const int UNIX_FD_VALUE = 0;
|
||||
|
||||
const std::string DEFAULT_STATE_VALUE{"default-state-value"};
|
||||
const uint32_t DEFAULT_ACTION_VALUE{999};
|
||||
const std::string DEFAULT_ACTION_VARIANT_VALUE{"ahoj"};
|
||||
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>& duration, ::std::ostream* stream)
|
||||
{
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::duration<double>>(duration);
|
||||
*stream << seconds.count() << "s";
|
||||
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";
|
||||
}
|
||||
|
||||
} // namespace testing::internal
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestAdaptor.cpp
|
||||
*
|
||||
@@ -25,31 +25,14 @@
|
||||
*/
|
||||
|
||||
#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::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
TestAdaptor::TestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path) :
|
||||
AdaptorInterfaces(connection, std::move(path))
|
||||
TestAdaptor::TestAdaptor(sdbus::IConnection& connection, const std::string& path) :
|
||||
AdaptorInterfaces(connection, path)
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
@@ -73,37 +56,37 @@ std::tuple<uint32_t, std::string> TestAdaptor::getTuple()
|
||||
return std::make_tuple(UINT32_VALUE, STRING_VALUE);
|
||||
}
|
||||
|
||||
double TestAdaptor::multiply(const int64_t& lhs, const double& rhs)
|
||||
double TestAdaptor::multiply(const int64_t& a, const double& b)
|
||||
{
|
||||
return lhs * rhs; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
|
||||
return a * b;
|
||||
}
|
||||
|
||||
void TestAdaptor::multiplyWithNoReply(const int64_t& lhs, const double& rhs)
|
||||
void TestAdaptor::multiplyWithNoReply(const int64_t& a, const double& b)
|
||||
{
|
||||
m_multiplyResult = lhs * rhs; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
|
||||
m_multiplyResult = a * b;
|
||||
m_wasMultiplyCalled = true;
|
||||
}
|
||||
|
||||
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> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
|
||||
{
|
||||
std::vector res{strct.get<1>()};
|
||||
auto vec = std::get<std::vector<int16_t>>(strct);
|
||||
res.insert(res.end(), vec.begin(), vec.end());
|
||||
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());
|
||||
return res;
|
||||
}
|
||||
|
||||
sdbus::Variant TestAdaptor::processVariant(const std::variant<int32_t, double, std::string>& var)
|
||||
sdbus::Variant TestAdaptor::processVariant(const sdbus::Variant& v)
|
||||
{
|
||||
sdbus::Variant res{static_cast<int32_t>(std::get<double>(var))};
|
||||
sdbus::Variant res{static_cast<int32_t>(v.get<double>())};
|
||||
return res;
|
||||
}
|
||||
|
||||
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> TestAdaptor::getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
|
||||
{
|
||||
std::map<int32_t, sdbus::Variant> res;
|
||||
for (auto item : vec)
|
||||
for (auto item : x)
|
||||
{
|
||||
res[item] = (item <= 0) ? std::get<0>(strct) : std::get<1>(strct);
|
||||
res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -113,24 +96,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>& strctA, const sdbus::Struct<int32_t, int64_t>& strctB)
|
||||
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
|
||||
{
|
||||
int32_t res{0};
|
||||
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)
|
||||
res += std::get<0>(a) + std::get<1>(a);
|
||||
res += std::get<0>(b) + std::get<1>(b);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& vec, const std::array<uint64_t, 3>& arr)
|
||||
uint32_t TestAdaptor::sumArrayItems(const std::vector<uint16_t>& a, const std::array<uint64_t, 3>& b)
|
||||
{
|
||||
uint32_t res{0};
|
||||
for (auto elem : vec)
|
||||
for (auto x : a)
|
||||
{
|
||||
res += elem;
|
||||
res += x;
|
||||
}
|
||||
for (auto elem : arr)
|
||||
for (auto x : b)
|
||||
{
|
||||
res += elem;
|
||||
res += x;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -140,23 +123,15 @@ uint32_t TestAdaptor::doOperation(const uint32_t& param)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(param));
|
||||
|
||||
m_methodCallMsg = std::make_unique<const Message>(getObject().getCurrentlyProcessedMessage());
|
||||
m_methodName = m_methodCallMsg->getMemberName();
|
||||
m_methodCallMemberName = m_methodCallMsg->getMemberName();
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
std::map<int32_t, std::string> TestAdaptor::doOperationWithLargeData(const std::map<int32_t, std::string>& largeParam)
|
||||
{
|
||||
m_methodCallMsg = std::make_unique<const Message>(getObject().getCurrentlyProcessedMessage());
|
||||
m_methodName = m_methodCallMsg->getMemberName();
|
||||
|
||||
return largeParam;
|
||||
}
|
||||
|
||||
void TestAdaptor::doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t param)
|
||||
{
|
||||
m_methodCallMsg = std::make_unique<const Message>(getObject().getCurrentlyProcessedMessage());
|
||||
m_methodName = m_methodCallMsg->getMemberName();
|
||||
m_methodCallMemberName = m_methodCallMsg->getMemberName();
|
||||
|
||||
if (param == 0)
|
||||
{
|
||||
@@ -174,27 +149,6 @@ void TestAdaptor::doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t pa
|
||||
}
|
||||
}
|
||||
|
||||
void TestAdaptor::doOperationAsyncWithLargeData(sdbus::Result<std::map<int32_t, std::string>>&& result, uint32_t param, const std::map<int32_t, std::string>& largeMap)
|
||||
{
|
||||
m_methodCallMsg = std::make_unique<const Message>(getObject().getCurrentlyProcessedMessage());
|
||||
m_methodName = m_methodCallMsg->getMemberName();
|
||||
|
||||
if (param == 0)
|
||||
{
|
||||
// Don't sleep and return the result from this thread
|
||||
result.returnResults(largeMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process asynchronously in another thread and return the result from there
|
||||
std::thread([param, largeMap, result = std::move(result)]()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(param));
|
||||
result.returnResults(largeMap);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
sdbus::Signature TestAdaptor::getSignature()
|
||||
{
|
||||
return SIGNATURE_VALUE;
|
||||
@@ -219,7 +173,7 @@ std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::
|
||||
23, // uint8_t
|
||||
{ // vector
|
||||
{ // struct
|
||||
sdbus::ObjectPath{"/object/path"}, // object path
|
||||
"/object/path", // object path
|
||||
false,
|
||||
Variant{3.14},
|
||||
{ // map
|
||||
@@ -229,7 +183,7 @@ std::unordered_map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::
|
||||
}
|
||||
}
|
||||
},
|
||||
sdbus::Signature{"a{t(a{ya(obva{is})}gs)}"}, // signature
|
||||
"a{t(a{ya(obva{is})}gs)}", // signature
|
||||
std::string{}
|
||||
}
|
||||
}
|
||||
@@ -258,16 +212,6 @@ void TestAdaptor::emitTwoSimpleSignals()
|
||||
emitSignalWithMap({});
|
||||
}
|
||||
|
||||
void TestAdaptor::sendLargeMessage(const std::map<int, std::string>& /*collection*/)
|
||||
{
|
||||
//printf("Adaptor: got collection with %zu items", collection.size());
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> TestAdaptor::returnDictionary(const std::map<std::string, sdbus::Variant>& dict)
|
||||
{
|
||||
return dict;
|
||||
}
|
||||
|
||||
std::string TestAdaptor::state()
|
||||
{
|
||||
return m_state;
|
||||
@@ -283,16 +227,6 @@ void TestAdaptor::action(const uint32_t& value)
|
||||
m_action = value;
|
||||
}
|
||||
|
||||
sdbus::Variant TestAdaptor::actionVariant()
|
||||
{
|
||||
return m_actionVariant;
|
||||
}
|
||||
|
||||
void TestAdaptor::actionVariant(const sdbus::Variant& value)
|
||||
{
|
||||
m_actionVariant = value;
|
||||
}
|
||||
|
||||
bool TestAdaptor::blocking()
|
||||
{
|
||||
return m_blocking;
|
||||
@@ -306,12 +240,12 @@ void TestAdaptor::blocking(const bool& value)
|
||||
m_blocking = value;
|
||||
}
|
||||
|
||||
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct)
|
||||
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
|
||||
{
|
||||
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(strct);
|
||||
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(s);
|
||||
}
|
||||
|
||||
std::string TestAdaptor::getExpectedXmlApiDescription()
|
||||
std::string TestAdaptor::getExpectedXmlApiDescription() const
|
||||
{
|
||||
return
|
||||
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
@@ -489,4 +423,4 @@ R"delimiter(
|
||||
)delimiter";
|
||||
}
|
||||
|
||||
} // namespace sdbus::test
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestAdaptor.h
|
||||
*
|
||||
@@ -35,22 +35,17 @@
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
namespace sdbus::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
class ObjectManagerTestAdaptor final : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
|
||||
{
|
||||
public:
|
||||
ObjectManagerTestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path) :
|
||||
ObjectManagerTestAdaptor(sdbus::IConnection& connection, std::string path) :
|
||||
AdaptorInterfaces(connection, std::move(path))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
ObjectManagerTestAdaptor(const ObjectManagerTestAdaptor&) = delete;
|
||||
ObjectManagerTestAdaptor& operator=(const ObjectManagerTestAdaptor&) = delete;
|
||||
ObjectManagerTestAdaptor(ObjectManagerTestAdaptor&&) = delete;
|
||||
ObjectManagerTestAdaptor& operator=(ObjectManagerTestAdaptor&&) = delete;
|
||||
|
||||
~ObjectManagerTestAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
@@ -62,29 +57,23 @@ class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integr
|
||||
, sdbus::ManagedObject_adaptor >
|
||||
{
|
||||
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(sdbus::IConnection& connection, const std::string& path);
|
||||
~TestAdaptor();
|
||||
|
||||
protected:
|
||||
void noArgNoReturn() override;
|
||||
int32_t getInt() override;
|
||||
std::tuple<uint32_t, std::string> getTuple() 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>& vec, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& strct) 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;
|
||||
sdbus::Variant processVariant(const sdbus::Variant& variant) override;
|
||||
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) 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>& 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 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;
|
||||
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;
|
||||
void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) override;
|
||||
sdbus::Signature getSignature() override;
|
||||
sdbus::ObjectPath getObjPath() override;
|
||||
sdbus::UnixFd getUnixFd() override;
|
||||
@@ -93,26 +82,21 @@ protected:
|
||||
void throwErrorWithNoReply() override;
|
||||
void doPrivilegedStuff() override;
|
||||
void emitTwoSimpleSignals() override;
|
||||
void sendLargeMessage(const std::map<int, std::string>& collection) override;
|
||||
std::map<std::string, sdbus::Variant> returnDictionary(const std::map<std::string, sdbus::Variant>& dict) override;
|
||||
|
||||
uint32_t action() override;
|
||||
void action(const uint32_t& value) override;
|
||||
sdbus::Variant actionVariant() override;
|
||||
void actionVariant(const sdbus::Variant& value) override;
|
||||
bool blocking() override;
|
||||
void blocking(const bool& value) override;
|
||||
std::string state() override;
|
||||
|
||||
public:
|
||||
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct);
|
||||
static std::string getExpectedXmlApiDescription() ;
|
||||
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
|
||||
std::string getExpectedXmlApiDescription() const;
|
||||
|
||||
private:
|
||||
const std::string m_state{DEFAULT_STATE_VALUE};
|
||||
uint32_t m_action{DEFAULT_ACTION_VALUE};
|
||||
bool m_blocking{DEFAULT_BLOCKING_VALUE};
|
||||
sdbus::Variant m_actionVariant{"ahoj"};
|
||||
|
||||
public: // for tests
|
||||
// For dont-expect-reply method call verifications
|
||||
@@ -121,7 +105,7 @@ public: // for tests
|
||||
mutable std::atomic<bool> m_wasThrowErrorCalled{false};
|
||||
|
||||
std::unique_ptr<const Message> m_methodCallMsg;
|
||||
MethodName m_methodName;
|
||||
std::string m_methodCallMemberName;
|
||||
std::unique_ptr<const Message> m_propertySetMsg;
|
||||
std::string m_propertySetSender;
|
||||
};
|
||||
@@ -131,9 +115,7 @@ class DummyTestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::i
|
||||
, sdbus::ManagedObject_adaptor >
|
||||
{
|
||||
public:
|
||||
DummyTestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath path)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
{}
|
||||
DummyTestAdaptor(sdbus::IConnection& connection, const std::string& path) : AdaptorInterfaces(connection, path) {}
|
||||
|
||||
protected:
|
||||
void noArgNoReturn() override {}
|
||||
@@ -142,15 +124,13 @@ protected:
|
||||
double multiply(const int64_t&, const double&) override { return {}; }
|
||||
void multiplyWithNoReply(const int64_t&, const double&) override {}
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>&) override { return {}; }
|
||||
sdbus::Variant processVariant(const std::variant<int32_t, double, std::string>&) override { return {}; }
|
||||
sdbus::Variant processVariant(const sdbus::Variant&) override { return {}; }
|
||||
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>&, const sdbus::Struct<sdbus::Variant, sdbus::Variant>&) override { return {}; }
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override { return {}; }
|
||||
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>&, const sdbus::Struct<int32_t, int64_t>&) override { return {}; }
|
||||
uint32_t sumArrayItems(const std::vector<uint16_t>&, const std::array<uint64_t, 3>&) override { return {}; }
|
||||
uint32_t doOperation(const uint32_t&) override { return {}; }
|
||||
std::map<int32_t, std::string> doOperationWithLargeData(const std::map<int32_t, std::string>&) override { return {}; }
|
||||
void doOperationAsync(sdbus::Result<uint32_t>&&, uint32_t) override {}
|
||||
void doOperationAsyncWithLargeData(sdbus::Result<std::map<int32_t, std::string>>&&, uint32_t, const std::map<int32_t, std::string>&) override {}
|
||||
sdbus::Signature getSignature() override { return {}; }
|
||||
sdbus::ObjectPath getObjPath() override { return {}; }
|
||||
sdbus::UnixFd getUnixFd() override { return {}; }
|
||||
@@ -159,18 +139,14 @@ protected:
|
||||
void throwErrorWithNoReply() override {}
|
||||
void doPrivilegedStuff() override {}
|
||||
void emitTwoSimpleSignals() override {}
|
||||
void sendLargeMessage(const std::map<int, std::string>&) override {}
|
||||
std::map<std::string, sdbus::Variant> returnDictionary(const std::map<std::string, sdbus::Variant>&) override { return {}; }
|
||||
|
||||
uint32_t action() override { return {}; }
|
||||
void action(const uint32_t&) override {}
|
||||
sdbus::Variant actionVariant() override { return {}; }
|
||||
void actionVariant(const sdbus::Variant&) override {}
|
||||
bool blocking() override { return {}; }
|
||||
void blocking(const bool&) override {}
|
||||
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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestFixture.cpp
|
||||
*
|
||||
@@ -25,14 +25,11 @@
|
||||
*/
|
||||
|
||||
#include "TestFixture.h"
|
||||
#include <memory>
|
||||
#include "sdbus-c++/IConnection.h"
|
||||
#include <thread>
|
||||
|
||||
namespace sdbus::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_adaptorConnection = sdbus::createBusConnection();
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_proxyConnection = sdbus::createBusConnection();
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_adaptorConnection = sdbus::createSystemBusConnection();
|
||||
std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_proxyConnection = sdbus::createSystemBusConnection();
|
||||
|
||||
#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++
|
||||
|
||||
@@ -44,4 +41,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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestFixture.h
|
||||
*
|
||||
@@ -41,34 +41,33 @@
|
||||
#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::test {
|
||||
|
||||
inline const uint32_t ANY_UNSIGNED_NUMBER{123};
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
class BaseTestFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
s_adaptorConnection->requestName(SERVICE_NAME);
|
||||
s_adaptorConnection->requestName(BUS_NAME);
|
||||
}
|
||||
|
||||
static void TearDownTestSuite()
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
s_adaptorConnection->releaseName(SERVICE_NAME);
|
||||
s_adaptorConnection->releaseName(BUS_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
void SetUp() override
|
||||
{
|
||||
m_objectManagerProxy = std::make_unique<ObjectManagerTestProxy>(*s_proxyConnection, SERVICE_NAME, MANAGER_PATH);
|
||||
m_proxy = std::make_unique<TestProxy>(*s_proxyConnection, SERVICE_NAME, OBJECT_PATH);
|
||||
m_objectManagerProxy = std::make_unique<ObjectManagerTestProxy>(*s_proxyConnection, BUS_NAME, MANAGER_PATH);
|
||||
m_proxy = std::make_unique<TestProxy>(*s_proxyConnection, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
m_objectManagerAdaptor = std::make_unique<ObjectManagerTestAdaptor>(*s_adaptorConnection, MANAGER_PATH);
|
||||
m_adaptor = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH);
|
||||
@@ -92,7 +91,7 @@ public:
|
||||
struct SdBusCppLoop{};
|
||||
struct SdEventLoop{};
|
||||
|
||||
template <typename EventLoop>
|
||||
template <typename _EventLoop>
|
||||
class TestFixture : public BaseTestFixture{};
|
||||
|
||||
// Fixture working upon internal sdbus-c++ event loop
|
||||
@@ -100,17 +99,17 @@ template <>
|
||||
class TestFixture<SdBusCppLoop> : public BaseTestFixture
|
||||
{
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
BaseTestFixture::SetUpTestSuite();
|
||||
BaseTestFixture::SetUpTestCase();
|
||||
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 TearDownTestSuite()
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
BaseTestFixture::TearDownTestSuite();
|
||||
BaseTestFixture::TearDownTestCase();
|
||||
s_adaptorConnection->leaveEventLoop();
|
||||
s_proxyConnection->leaveEventLoop();
|
||||
}
|
||||
@@ -123,7 +122,7 @@ template <>
|
||||
class TestFixture<SdEventLoop> : public BaseTestFixture
|
||||
{
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
sd_event_new(&s_adaptorSdEvent);
|
||||
sd_event_new(&s_proxySdEvent);
|
||||
@@ -132,7 +131,7 @@ public:
|
||||
s_proxyConnection->attachSdEventLoop(s_proxySdEvent);
|
||||
|
||||
s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
auto exitHandler = [](sd_event_source *src, auto...){ return sd_event_exit(sd_event_source_get_event(src), 0); };
|
||||
auto exitHandler = [](sd_event_source *s, auto...){ return sd_event_exit(sd_event_source_get_event(s), 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);
|
||||
|
||||
@@ -145,11 +144,11 @@ public:
|
||||
sd_event_loop(s_proxySdEvent);
|
||||
});
|
||||
|
||||
BaseTestFixture::SetUpTestSuite();
|
||||
BaseTestFixture::SetUpTestCase();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals
|
||||
}
|
||||
|
||||
static void TearDownTestSuite()
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
(void)eventfd_write(s_eventExitFd, 1);
|
||||
|
||||
@@ -160,7 +159,7 @@ public:
|
||||
sd_event_unref(s_proxySdEvent);
|
||||
close(s_eventExitFd);
|
||||
|
||||
BaseTestFixture::TearDownTestSuite();
|
||||
BaseTestFixture::TearDownTestCase();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -171,24 +170,24 @@ private:
|
||||
static int s_eventExitFd;
|
||||
};
|
||||
|
||||
using EventLoopTags = ::testing::Types<SdBusCppLoop, SdEventLoop>;
|
||||
typedef ::testing::Types<SdBusCppLoop, SdEventLoop> EventLoopTags;
|
||||
|
||||
#else // SDBUS_basu
|
||||
using EventLoopTags = ::testing::Types<SdBusCppLoop>;
|
||||
typedef ::testing::Types<SdBusCppLoop> EventLoopTags;
|
||||
#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
|
||||
@@ -196,7 +195,7 @@ class TestFixtureWithDirectConnection : public ::testing::Test
|
||||
private:
|
||||
void SetUp() override
|
||||
{
|
||||
const int sock = openUnixSocket();
|
||||
int sock = openUnixSocket();
|
||||
createClientAndServerConnections(sock);
|
||||
createAdaptorAndProxyObjects();
|
||||
}
|
||||
@@ -211,19 +210,18 @@ private:
|
||||
|
||||
static int openUnixSocket()
|
||||
{
|
||||
const int sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
int sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
assert(sock >= 0);
|
||||
|
||||
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());
|
||||
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());
|
||||
|
||||
unlink(DIRECT_CONNECTION_SOCKET_PATH.c_str());
|
||||
|
||||
umask(0000);
|
||||
[[maybe_unused]] int r = bind(sock, reinterpret_cast<const sockaddr*>(&saddr), sizeof(saddr.sun_path));
|
||||
[[maybe_unused]] int r = bind(sock, (const sockaddr*) &sa, sizeof(sa.sun_path));
|
||||
assert(r >= 0);
|
||||
|
||||
r = listen(sock, 5);
|
||||
@@ -236,7 +234,7 @@ private:
|
||||
{
|
||||
std::thread t([&]()
|
||||
{
|
||||
auto fd = accept4(sock, nullptr, nullptr, /*SOCK_NONBLOCK|*/SOCK_CLOEXEC);
|
||||
auto fd = accept4(sock, NULL, NULL, /*SOCK_NONBLOCK|*/SOCK_CLOEXEC);
|
||||
m_adaptorConnection = sdbus::createServerBus(fd);
|
||||
// This is necessary so that createDirectBusConnection() below does not block
|
||||
m_adaptorConnection->enterEventLoopAsync();
|
||||
@@ -265,14 +263,14 @@ public:
|
||||
std::unique_ptr<TestProxy> m_proxy;
|
||||
};
|
||||
|
||||
template <typename Fnc>
|
||||
inline bool waitUntil(const Fnc& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
|
||||
template <typename _Fnc>
|
||||
inline bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
std::chrono::milliseconds elapsed{};
|
||||
const std::chrono::milliseconds step{5ms};
|
||||
do { // NOLINT(cppcoreguidelines-avoid-do-while)
|
||||
std::chrono::milliseconds step{5ms};
|
||||
do {
|
||||
std::this_thread::sleep_for(step);
|
||||
elapsed += step;
|
||||
if (elapsed > timeout)
|
||||
@@ -287,6 +285,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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestProxy.cpp
|
||||
*
|
||||
@@ -25,41 +25,31 @@
|
||||
*/
|
||||
|
||||
#include "TestProxy.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include "Defs.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace sdbus::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
TestProxy::TestProxy(ServiceName destination, ObjectPath objectPath)
|
||||
TestProxy::TestProxy(std::string destination, std::string 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>>& strct){ this->onSignalWithoutRegistration(strct); });
|
||||
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
|
||||
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
TestProxy::TestProxy(ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t)
|
||||
TestProxy::TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath), dont_run_event_loop_thread)
|
||||
{
|
||||
// It doesn't make sense to register any signals here since proxy upon a D-Bus connection with no event loop thread
|
||||
// will not receive any incoming messages except replies to synchronous D-Bus calls.
|
||||
}
|
||||
|
||||
TestProxy::TestProxy(sdbus::IConnection& connection, ServiceName destination, ObjectPath objectPath)
|
||||
TestProxy::TestProxy(sdbus::IConnection& connection, std::string destination, std::string 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>>& strct){ this->onSignalWithoutRegistration(strct); });
|
||||
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
|
||||
|
||||
registerProxy();
|
||||
}
|
||||
@@ -72,7 +62,7 @@ TestProxy::~TestProxy()
|
||||
void TestProxy::onSimpleSignal()
|
||||
{
|
||||
m_signalMsg = std::make_unique<sdbus::Message>(getProxy().getCurrentlyProcessedMessage());
|
||||
m_signalName = m_signalMsg->getMemberName();
|
||||
m_signalMemberName = m_signalMsg->getMemberName();
|
||||
|
||||
m_gotSimpleSignal = true;
|
||||
}
|
||||
@@ -89,22 +79,21 @@ void TestProxy::onSignalWithVariant(const sdbus::Variant& aVariant)
|
||||
m_gotSignalWithVariant = true;
|
||||
}
|
||||
|
||||
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct)
|
||||
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
|
||||
{
|
||||
// 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>(strct)] = static_cast<std::string>(std::get<0>(std::get<1>(strct)));
|
||||
m_signatureFromSignal[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
|
||||
m_gotSignalWithSignature = true;
|
||||
}
|
||||
|
||||
void TestProxy::onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const
|
||||
void TestProxy::onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error)
|
||||
{
|
||||
if (m_DoOperationClientSideAsyncReplyHandler)
|
||||
m_DoOperationClientSideAsyncReplyHandler(returnValue, std::move(error));
|
||||
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
|
||||
}
|
||||
|
||||
void TestProxy::onPropertiesChanged( const sdbus::InterfaceName& interfaceName
|
||||
, const std::map<PropertyName, sdbus::Variant>& changedProperties
|
||||
, const std::vector<PropertyName>& invalidatedProperties )
|
||||
void TestProxy::onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties )
|
||||
{
|
||||
if (m_onPropertiesChangedHandler)
|
||||
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
|
||||
@@ -118,21 +107,11 @@ 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 = 0;
|
||||
uint32_t result;
|
||||
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(timeout).withArguments(param).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
MethodReply TestProxy::doOperationOnBasicAPILevel(uint32_t param)
|
||||
{
|
||||
auto methodCall = getProxy().createMethodCall(test::INTERFACE_NAME, MethodName{"doOperation"});
|
||||
methodCall << param;
|
||||
|
||||
m_methodCallMsg = std::make_unique<MethodCall>(methodCall);
|
||||
|
||||
return getProxy().callMethod(methodCall);
|
||||
}
|
||||
|
||||
sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperation")
|
||||
@@ -144,17 +123,6 @@ sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
|
||||
});
|
||||
}
|
||||
|
||||
Slot TestProxy::doOperationClientSideAsync(uint32_t param, sdbus::return_slot_t)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperation")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.withArguments(param)
|
||||
.uponReplyInvoke([this](std::optional<sdbus::Error> error, uint32_t returnValue)
|
||||
{
|
||||
this->onDoOperationReply(returnValue, std::move(error));
|
||||
}, sdbus::return_slot);
|
||||
}
|
||||
|
||||
std::future<uint32_t> TestProxy::doOperationClientSideAsync(uint32_t param, with_future_t)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperation")
|
||||
@@ -165,20 +133,12 @@ std::future<uint32_t> TestProxy::doOperationClientSideAsync(uint32_t param, with
|
||||
|
||||
std::future<MethodReply> TestProxy::doOperationClientSideAsyncOnBasicAPILevel(uint32_t param)
|
||||
{
|
||||
auto methodCall = getProxy().createMethodCall(sdbus::test::INTERFACE_NAME, sdbus::MethodName{"doOperation"});
|
||||
auto methodCall = getProxy().createMethodCall(sdbus::test::INTERFACE_NAME, "doOperation");
|
||||
methodCall << param;
|
||||
|
||||
return getProxy().callMethodAsync(methodCall, sdbus::with_future);
|
||||
}
|
||||
|
||||
std::future<std::map<int32_t, std::string>> TestProxy::doOperationWithLargeDataClientSideAsync(const std::map<int32_t, std::string>& largeParam, with_future_t)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperationWithLargeData")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.withArguments(largeParam)
|
||||
.getResultAsFuture<std::map<int32_t, std::string>>();
|
||||
}
|
||||
|
||||
void TestProxy::doErroneousOperationClientSideAsync()
|
||||
{
|
||||
getProxy().callMethodAsync("throwError")
|
||||
@@ -196,38 +156,6 @@ 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;
|
||||
@@ -243,16 +171,15 @@ void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microse
|
||||
|
||||
int32_t TestProxy::callNonexistentMethod()
|
||||
{
|
||||
int32_t result = 0;
|
||||
int32_t result;
|
||||
getProxy().callMethod("callNonexistentMethod").onInterface(sdbus::test::INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t TestProxy::callMethodOnNonexistentInterface()
|
||||
{
|
||||
sdbus::InterfaceName const nonexistentInterfaceName{"sdbuscpp.interface.that.does.not.exist"};
|
||||
int32_t result = 0;
|
||||
getProxy().callMethod("someMethod").onInterface(nonexistentInterfaceName).storeResultsTo(result);
|
||||
int32_t result;
|
||||
getProxy().callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -261,4 +188,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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TestProxy.h
|
||||
*
|
||||
@@ -35,42 +35,37 @@
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
namespace sdbus::test {
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
class ObjectManagerTestProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
|
||||
{
|
||||
public:
|
||||
ObjectManagerTestProxy(sdbus::IConnection& connection, ServiceName destination, ObjectPath objectPath)
|
||||
ObjectManagerTestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
ObjectManagerTestProxy(const ObjectManagerTestProxy&) = delete;
|
||||
ObjectManagerTestProxy& operator=(const ObjectManagerTestProxy&) = delete;
|
||||
ObjectManagerTestProxy(ObjectManagerTestProxy&&) = delete;
|
||||
ObjectManagerTestProxy& operator=(ObjectManagerTestProxy&&) = delete;
|
||||
|
||||
~ObjectManagerTestProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
protected:
|
||||
void onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>& interfacesAndProperties) override
|
||||
void onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
|
||||
{
|
||||
if (m_onInterfacesAddedHandler)
|
||||
m_onInterfacesAddedHandler(objectPath, interfacesAndProperties);
|
||||
}
|
||||
|
||||
void onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector<sdbus::InterfaceName>& interfaces) override
|
||||
void onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces) override
|
||||
{
|
||||
if (m_onInterfacesRemovedHandler)
|
||||
m_onInterfacesRemovedHandler(objectPath, interfaces);
|
||||
}
|
||||
|
||||
public: // for tests
|
||||
std::function<void(const sdbus::ObjectPath&, const std::map<sdbus::InterfaceName, std::map<PropertyName, sdbus::Variant>>&)> m_onInterfacesAddedHandler;
|
||||
std::function<void(const sdbus::ObjectPath&, const std::vector<sdbus::InterfaceName>&)> m_onInterfacesRemovedHandler;
|
||||
std::function<void(const sdbus::ObjectPath&, const std::map<std::string, std::map<std::string, sdbus::Variant>>&)> m_onInterfacesAddedHandler;
|
||||
std::function<void(const sdbus::ObjectPath&, const std::vector<std::string>&)> m_onInterfacesRemovedHandler;
|
||||
};
|
||||
|
||||
class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
|
||||
@@ -79,13 +74,9 @@ class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integratio
|
||||
, sdbus::Properties_proxy >
|
||||
{
|
||||
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(std::string destination, std::string objectPath);
|
||||
TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t);
|
||||
TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath);
|
||||
~TestProxy();
|
||||
|
||||
protected:
|
||||
@@ -93,50 +84,43 @@ 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>>& strct);
|
||||
void onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const;
|
||||
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
|
||||
void onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error);
|
||||
|
||||
// Signals of standard D-Bus interfaces
|
||||
void onPropertiesChanged( const sdbus::InterfaceName& interfaceName
|
||||
, const std::map<PropertyName, sdbus::Variant>& changedProperties
|
||||
, const std::vector<PropertyName>& invalidatedProperties ) override;
|
||||
void onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties ) override;
|
||||
|
||||
public:
|
||||
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, std::optional<sdbus::Error> err)> handler);
|
||||
uint32_t doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||
MethodReply doOperationOnBasicAPILevel(uint32_t param);
|
||||
sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param);
|
||||
[[nodiscard]] sdbus::Slot doOperationClientSideAsync(uint32_t param, sdbus::return_slot_t);
|
||||
std::future<uint32_t> doOperationClientSideAsync(uint32_t param, with_future_t);
|
||||
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: (Kept public for tests)
|
||||
//private:
|
||||
public: // for tests
|
||||
int m_SimpleSignals = 0;
|
||||
std::atomic<bool> m_gotSimpleSignal{false};
|
||||
std::atomic<bool> m_gotSignalWithMap{false};
|
||||
std::map<int32_t, std::string> m_mapFromSignal;
|
||||
std::atomic<bool> m_gotSignalWithVariant{false};
|
||||
double m_variantFromSignal{};
|
||||
double m_variantFromSignal;
|
||||
std::atomic<bool> m_gotSignalWithSignature{false};
|
||||
std::map<std::string, Signature> m_signatureFromSignal;
|
||||
std::map<std::string, std::string> m_signatureFromSignal;
|
||||
|
||||
std::function<void(uint32_t res, std::optional<sdbus::Error> err)> m_DoOperationClientSideAsyncReplyHandler;
|
||||
std::function<void(const sdbus::InterfaceName&, const std::map<PropertyName, sdbus::Variant>&, const std::vector<PropertyName>&)> m_onPropertiesChangedHandler;
|
||||
std::function<void(const std::string&, const std::map<std::string, sdbus::Variant>&, const std::vector<std::string>&)> m_onPropertiesChangedHandler;
|
||||
|
||||
std::unique_ptr<const MethodCall> m_methodCallMsg;
|
||||
std::unique_ptr<const Message> m_signalMsg;
|
||||
SignalName m_signalName;
|
||||
std::string m_signalMemberName;
|
||||
};
|
||||
|
||||
class DummyTestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
|
||||
@@ -145,8 +129,8 @@ class DummyTestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integ
|
||||
, sdbus::Properties_proxy >
|
||||
{
|
||||
public:
|
||||
DummyTestProxy(ServiceName destination, ObjectPath objectPath)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath))
|
||||
DummyTestProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(destination, objectPath)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -156,12 +140,12 @@ protected:
|
||||
void onSignalWithVariant(const sdbus::Variant&) override {}
|
||||
|
||||
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>&) {}
|
||||
void onDoOperationReply(uint32_t, const std::optional<sdbus::Error>&) {}
|
||||
void onDoOperationReply(uint32_t, 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 {}
|
||||
void onPropertiesChanged( const std::string&, const std::map<std::string, sdbus::Variant>&, const std::vector<std::string>& ) override {}
|
||||
};
|
||||
|
||||
} // namespace sdbus::test
|
||||
}}
|
||||
|
||||
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */
|
||||
|
||||
+10
-21
@@ -20,35 +20,33 @@ public:
|
||||
|
||||
protected:
|
||||
integrationtests_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
integrationtests_adaptor(const integrationtests_adaptor&) = delete;
|
||||
integrationtests_adaptor& operator=(const integrationtests_adaptor&) = delete;
|
||||
integrationtests_adaptor(integrationtests_adaptor&&) = delete;
|
||||
integrationtests_adaptor& operator=(integrationtests_adaptor&&) = delete;
|
||||
integrationtests_adaptor(integrationtests_adaptor&&) = default;
|
||||
integrationtests_adaptor& operator=(integrationtests_adaptor&&) = default;
|
||||
|
||||
~integrationtests_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::setInterfaceFlags().markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL)
|
||||
object_->addVTable( sdbus::setInterfaceFlags().markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL)
|
||||
, sdbus::registerMethod("noArgNoReturn").implementedAs([this](){ return this->noArgNoReturn(); })
|
||||
, sdbus::registerMethod("getInt").withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); })
|
||||
, sdbus::registerMethod("getTuple").withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); })
|
||||
, sdbus::registerMethod("multiply").withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); })
|
||||
, sdbus::registerMethod("multiplyWithNoReply").withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply()
|
||||
, sdbus::registerMethod("getInts16FromStruct").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); })
|
||||
, sdbus::registerMethod("processVariant").withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const std::variant<int32_t, double, std::string>& variant){ return this->processVariant(variant); })
|
||||
, sdbus::registerMethod("processVariant").withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); })
|
||||
, sdbus::registerMethod("getMapOfVariants").withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); })
|
||||
, sdbus::registerMethod("getStructInStruct").withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); })
|
||||
, sdbus::registerMethod("sumStructItems").withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); })
|
||||
, sdbus::registerMethod("sumArrayItems").withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1){ return this->sumArrayItems(arg0, arg1); })
|
||||
, sdbus::registerMethod("doOperation").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); })
|
||||
, sdbus::registerMethod("doOperationWithLargeData").withInputParamNames("largeMap").withOutputParamNames("largeMap").implementedAs([this](const std::map<int32_t, std::string>& largeMap){ return this->doOperationWithLargeData(largeMap); })
|
||||
, sdbus::registerMethod("doOperationAsync").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); })
|
||||
, sdbus::registerMethod("doOperationAsyncWithLargeData").withInputParamNames("arg0", "largeMap").withOutputParamNames("largeMap").implementedAs([this](sdbus::Result<std::map<int32_t, std::string>>&& result, uint32_t arg0, const std::map<int32_t, std::string>& largeMap){ this->doOperationAsyncWithLargeData(std::move(result), std::move(arg0), largeMap); })
|
||||
, sdbus::registerMethod("getSignature").withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); })
|
||||
, sdbus::registerMethod("getObjPath").withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); })
|
||||
, sdbus::registerMethod("getUnixFd").withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); })
|
||||
@@ -57,13 +55,10 @@ protected:
|
||||
, sdbus::registerMethod("throwErrorWithNoReply").implementedAs([this](){ return this->throwErrorWithNoReply(); }).withNoReply()
|
||||
, sdbus::registerMethod("doPrivilegedStuff").implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged()
|
||||
, sdbus::registerMethod("emitTwoSimpleSignals").implementedAs([this](){ return this->emitTwoSimpleSignals(); })
|
||||
, sdbus::registerMethod("sendLargeMessage").implementedAs([this](const std::map<int, std::string>& collection){ this->sendLargeMessage(collection); })
|
||||
, sdbus::registerMethod("returnDictionary").implementedAs([this](const std::map<std::string, sdbus::Variant>& dictionary){ return this->returnDictionary(dictionary); })
|
||||
, sdbus::registerSignal("simpleSignal").markAsDeprecated()
|
||||
, sdbus::registerSignal("signalWithMap").withParameters<std::map<int32_t, std::string>>("aMap")
|
||||
, sdbus::registerSignal("signalWithVariant").withParameters<sdbus::Variant>("aVariant")
|
||||
, sdbus::registerProperty("action").withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL)
|
||||
, sdbus::registerProperty("actionVariant").withGetter([this](){ return this->actionVariant(); }).withSetter([this](const sdbus::Variant& value){ this->actionVariant(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL)
|
||||
, sdbus::registerProperty("blocking").withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); })
|
||||
, sdbus::registerProperty("state").withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE)
|
||||
).forInterface(INTERFACE_NAME);
|
||||
@@ -72,17 +67,17 @@ protected:
|
||||
public:
|
||||
void emitSimpleSignal()
|
||||
{
|
||||
m_object.emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
object_->emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void emitSignalWithMap(const std::map<int32_t, std::string>& aMap)
|
||||
{
|
||||
m_object.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
|
||||
object_->emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
|
||||
}
|
||||
|
||||
void emitSignalWithVariant(const sdbus::Variant& aVariant)
|
||||
{
|
||||
m_object.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
|
||||
object_->emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -92,15 +87,13 @@ private:
|
||||
virtual double multiply(const int64_t& a, const double& b) = 0;
|
||||
virtual void multiplyWithNoReply(const int64_t& a, const double& b) = 0;
|
||||
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) = 0;
|
||||
virtual sdbus::Variant processVariant(const std::variant<int32_t, double, std::string>& variant) = 0;
|
||||
virtual sdbus::Variant processVariant(const sdbus::Variant& variant) = 0;
|
||||
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) = 0;
|
||||
virtual sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() = 0;
|
||||
virtual int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) = 0;
|
||||
virtual uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1) = 0;
|
||||
virtual uint32_t doOperation(const uint32_t& arg0) = 0;
|
||||
virtual std::map<int32_t, std::string> doOperationWithLargeData(const std::map<int32_t, std::string>& largeParam) = 0;
|
||||
virtual void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) = 0;
|
||||
virtual void doOperationAsyncWithLargeData(sdbus::Result<std::map<int32_t, std::string>>&& result, uint32_t arg0, const std::map<int32_t, std::string>& largeParam) = 0;
|
||||
virtual sdbus::Signature getSignature() = 0;
|
||||
virtual sdbus::ObjectPath getObjPath() = 0;
|
||||
virtual sdbus::UnixFd getUnixFd() = 0;
|
||||
@@ -109,20 +102,16 @@ private:
|
||||
virtual void throwErrorWithNoReply() = 0;
|
||||
virtual void doPrivilegedStuff() = 0;
|
||||
virtual void emitTwoSimpleSignals() = 0;
|
||||
virtual void sendLargeMessage(const std::map<int, std::string>& collection) = 0;
|
||||
virtual std::map<std::string, sdbus::Variant> returnDictionary(const std::map<std::string, sdbus::Variant>& dict) = 0;
|
||||
|
||||
private:
|
||||
virtual uint32_t action() = 0;
|
||||
virtual sdbus::Variant actionVariant() = 0;
|
||||
virtual void action(const uint32_t& value) = 0;
|
||||
virtual void actionVariant(const sdbus::Variant& value) = 0;
|
||||
virtual bool blocking() = 0;
|
||||
virtual void blocking(const bool& value) = 0;
|
||||
virtual std::string state() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
+34
-70
@@ -20,22 +20,22 @@ public:
|
||||
|
||||
protected:
|
||||
integrationtests_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
integrationtests_proxy(const integrationtests_proxy&) = delete;
|
||||
integrationtests_proxy& operator=(const integrationtests_proxy&) = delete;
|
||||
integrationtests_proxy(integrationtests_proxy&&) = delete;
|
||||
integrationtests_proxy& operator=(integrationtests_proxy&&) = delete;
|
||||
integrationtests_proxy(integrationtests_proxy&&) = default;
|
||||
integrationtests_proxy& operator=(integrationtests_proxy&&) = default;
|
||||
|
||||
~integrationtests_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
simpleSignalSlot_ = m_proxy.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }, sdbus::return_slot);
|
||||
m_proxy.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
|
||||
m_proxy.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
|
||||
simpleSignalSlot_ = proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }, sdbus::return_slot);
|
||||
proxy_->uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
|
||||
proxy_->uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
|
||||
}
|
||||
|
||||
virtual void onSimpleSignal() = 0;
|
||||
@@ -45,163 +45,137 @@ protected:
|
||||
public:
|
||||
void noArgNoReturn()
|
||||
{
|
||||
m_proxy.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
int32_t getInt()
|
||||
{
|
||||
int32_t result;
|
||||
m_proxy.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::tuple<uint32_t, std::string> getTuple()
|
||||
{
|
||||
std::tuple<uint32_t, std::string> result;
|
||||
m_proxy.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
double multiply(const int64_t& a, const double& b)
|
||||
{
|
||||
double result;
|
||||
m_proxy.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
proxy_->callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void multiplyWithNoReply(const int64_t& a, const double& b)
|
||||
{
|
||||
m_proxy.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
|
||||
proxy_->callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
|
||||
}
|
||||
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0)
|
||||
{
|
||||
std::vector<int16_t> result;
|
||||
m_proxy.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
proxy_->callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Variant processVariant(const sdbus::Variant& variant)
|
||||
{
|
||||
sdbus::Variant result;
|
||||
m_proxy.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::variant<int32_t, double, std::string> processVariant(const std::variant<int32_t, double, std::string>& variant)
|
||||
{
|
||||
std::variant<int32_t, double, std::string> result;
|
||||
m_proxy.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
|
||||
proxy_->callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
|
||||
{
|
||||
std::map<int32_t, sdbus::Variant> result;
|
||||
m_proxy.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
|
||||
proxy_->callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct()
|
||||
{
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> result;
|
||||
m_proxy.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1)
|
||||
{
|
||||
int32_t result;
|
||||
m_proxy.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
proxy_->callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t sumArrayItems(const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1)
|
||||
{
|
||||
uint32_t result;
|
||||
m_proxy.callMethod("sumArrayItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
proxy_->callMethod("sumArrayItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperation(const uint32_t& arg0)
|
||||
{
|
||||
uint32_t result;
|
||||
m_proxy.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<int32_t, std::string> doOperationWithLargeData(const std::map<int32_t, std::string>& largeParam)
|
||||
{
|
||||
std::map<int32_t, std::string> result;
|
||||
m_proxy.callMethod("doOperationWithLargeData").onInterface(INTERFACE_NAME).withArguments(largeParam).storeResultsTo(result);
|
||||
proxy_->callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperationAsync(const uint32_t& arg0)
|
||||
{
|
||||
uint32_t result;
|
||||
m_proxy.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<int32_t, std::string> doOperationAsyncWithLargeData(const uint32_t& arg0, const std::map<int32_t, std::string>& largeParam)
|
||||
{
|
||||
std::map<int32_t, std::string> result;
|
||||
m_proxy.callMethod("doOperationAsyncWithLargeData").onInterface(INTERFACE_NAME).withArguments(arg0, largeParam).storeResultsTo(result);
|
||||
proxy_->callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Signature getSignature()
|
||||
{
|
||||
sdbus::Signature result;
|
||||
m_proxy.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::ObjectPath getObjPath()
|
||||
{
|
||||
sdbus::ObjectPath result;
|
||||
m_proxy.callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::UnixFd getUnixFd()
|
||||
{
|
||||
sdbus::UnixFd result;
|
||||
m_proxy.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::unordered_map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex()
|
||||
{
|
||||
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::unordered_map<int32_t, std::string>>>>, sdbus::Signature, std::string>> result;
|
||||
m_proxy.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void throwError()
|
||||
{
|
||||
m_proxy.callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void throwErrorWithNoReply()
|
||||
{
|
||||
m_proxy.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
proxy_->callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
}
|
||||
|
||||
void doPrivilegedStuff()
|
||||
{
|
||||
m_proxy.callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void emitTwoSimpleSignals()
|
||||
{
|
||||
m_proxy.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void sendLargeMessage(const std::map<int, std::string>& collection)
|
||||
{
|
||||
m_proxy.callMethod("sendLargeMessage").onInterface(INTERFACE_NAME).withArguments(collection);
|
||||
proxy_->callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void unregisterSimpleSignalHandler()
|
||||
@@ -211,47 +185,37 @@ public:
|
||||
|
||||
void reRegisterSimpleSignalHandler()
|
||||
{
|
||||
simpleSignalSlot_ = m_proxy.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }, sdbus::return_slot);
|
||||
simpleSignalSlot_ = proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }, sdbus::return_slot);
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t action()
|
||||
{
|
||||
return m_proxy.getProperty("action").onInterface(INTERFACE_NAME).get<uint32_t>();
|
||||
return proxy_->getProperty("action").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void action(const uint32_t& value)
|
||||
{
|
||||
m_proxy.setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
sdbus::Variant actionVariant()
|
||||
{
|
||||
return m_proxy.getProperty("actionVariant").onInterface(INTERFACE_NAME).get<sdbus::Variant>();
|
||||
}
|
||||
|
||||
void actionVariant(const sdbus::Variant& value)
|
||||
{
|
||||
m_proxy.setProperty("actionVariant").onInterface(INTERFACE_NAME).toValue({value, sdbus::embed_variant});
|
||||
proxy_->setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool blocking()
|
||||
{
|
||||
return m_proxy.getProperty("blocking").onInterface(INTERFACE_NAME).get<bool>();
|
||||
return proxy_->getProperty("blocking").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void blocking(const bool& value)
|
||||
{
|
||||
m_proxy.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
|
||||
proxy_->setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
std::string state()
|
||||
{
|
||||
return m_proxy.getProperty("state").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
return proxy_->getProperty("state").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
sdbus::Slot simpleSignalSlot_;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file sdbus-c++-integration-tests.cpp
|
||||
*
|
||||
|
||||
+29
-42
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file client.cpp
|
||||
*
|
||||
@@ -25,44 +24,37 @@
|
||||
*/
|
||||
|
||||
#include "perftests-proxy.h"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#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; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
uint64_t totalDuration = 0;
|
||||
|
||||
class PerftestProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::perftests_proxy>
|
||||
{
|
||||
public:
|
||||
PerftestProxy(sdbus::ServiceName destination, sdbus::ObjectPath objectPath)
|
||||
PerftestProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
PerftestProxy(const PerftestProxy&) = delete;
|
||||
PerftestProxy& operator=(const PerftestProxy&) = delete;
|
||||
PerftestProxy(PerftestProxy&&) = delete;
|
||||
PerftestProxy& operator=(PerftestProxy&&) = delete;
|
||||
|
||||
~PerftestProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
protected:
|
||||
void onDataSignal([[maybe_unused]] const std::string& data) override
|
||||
virtual void onDataSignal([[maybe_unused]] const std::string& data) override
|
||||
{
|
||||
static unsigned int counter = 0;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> startTime;
|
||||
@@ -78,7 +70,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" << '\n';
|
||||
std::cout << "Received " << m_msgCount << " signals in: " << duration << " ms" << std::endl;
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
@@ -97,13 +89,8 @@ std::string createRandomString(size_t length)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[ random() % max_index ];
|
||||
return charset[ rand() % 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;
|
||||
@@ -113,49 +100,49 @@ std::string createRandomString(size_t length)
|
||||
//-----------------------------------------
|
||||
int main(int /*argc*/, char */*argv*/[])
|
||||
{
|
||||
sdbus::ServiceName destination{"org.sdbuscpp.perftests"};
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/perftests"};
|
||||
PerftestProxy client(std::move(destination), std::move(objectPath));
|
||||
const char* destinationName = "org.sdbuscpp.perftests";
|
||||
const char* objectPath = "/org/sdbuscpp/perftests";
|
||||
PerftestProxy client(destinationName, objectPath);
|
||||
|
||||
const unsigned int repetitions{20};
|
||||
unsigned int const msgCount = 1000;
|
||||
unsigned int msgCount = 1000;
|
||||
unsigned int msgSize{};
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
|
||||
std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int i = 0; i < repetitions; ++i)
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << '\n' << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
|
||||
std::cout << std::endl << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl;
|
||||
client.m_msgCount = msgCount; client.m_msgSize = msgSize;
|
||||
for (unsigned int i = 0; i < repetitions; ++i)
|
||||
for (unsigned int r = 0; r < repetitions; ++r)
|
||||
{
|
||||
client.sendDataSignals(msgCount, msgSize);
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 20;
|
||||
std::cout << '\n' << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
|
||||
for (unsigned int i = 0; i < repetitions; ++i)
|
||||
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)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int j = 0; j < msgCount; j++)
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
@@ -165,23 +152,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" << '\n';
|
||||
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
msgSize = 1000;
|
||||
std::cout << '\n' << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << '\n' << '\n';
|
||||
for (unsigned int i = 0; i < repetitions; ++i)
|
||||
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)
|
||||
{
|
||||
auto str1 = createRandomString(msgSize/2);
|
||||
auto str2 = createRandomString(msgSize/2);
|
||||
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
for (unsigned int j = 0; j < msgCount; j++)
|
||||
for (unsigned int i = 0; i < msgCount; i++)
|
||||
{
|
||||
auto result = client.concatenateTwoStrings(str1, str2);
|
||||
|
||||
@@ -191,12 +178,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" << '\n';
|
||||
std::cout << "Called " << msgCount << " methods in: " << duration << " ms" << std::endl;
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << '\n';
|
||||
std::cout << "AVERAGE: " << (totalDuration/repetitions) << " ms" << std::endl;
|
||||
totalDuration = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
+6
-6
@@ -20,20 +20,20 @@ public:
|
||||
|
||||
protected:
|
||||
perftests_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
perftests_adaptor(const perftests_adaptor&) = delete;
|
||||
perftests_adaptor& operator=(const perftests_adaptor&) = delete;
|
||||
perftests_adaptor(perftests_adaptor&&) = delete;
|
||||
perftests_adaptor& operator=(perftests_adaptor&&) = delete;
|
||||
perftests_adaptor(perftests_adaptor&&) = default;
|
||||
perftests_adaptor& operator=(perftests_adaptor&&) = default;
|
||||
|
||||
~perftests_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerMethod("sendDataSignals").withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); })
|
||||
object_->addVTable( sdbus::registerMethod("sendDataSignals").withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); })
|
||||
, sdbus::registerMethod("concatenateTwoStrings").withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); })
|
||||
, sdbus::registerSignal("dataSignal").withParameters<std::string>("data")
|
||||
).forInterface(INTERFACE_NAME);
|
||||
@@ -42,7 +42,7 @@ protected:
|
||||
public:
|
||||
void emitDataSignal(const std::string& data)
|
||||
{
|
||||
m_object.emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
|
||||
object_->emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -50,7 +50,7 @@ private:
|
||||
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
+7
-7
@@ -20,20 +20,20 @@ public:
|
||||
|
||||
protected:
|
||||
perftests_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
perftests_proxy(const perftests_proxy&) = delete;
|
||||
perftests_proxy& operator=(const perftests_proxy&) = delete;
|
||||
perftests_proxy(perftests_proxy&&) = delete;
|
||||
perftests_proxy& operator=(perftests_proxy&&) = delete;
|
||||
perftests_proxy(perftests_proxy&&) = default;
|
||||
perftests_proxy& operator=(perftests_proxy&&) = default;
|
||||
|
||||
~perftests_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
m_proxy.uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
|
||||
proxy_->uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
|
||||
}
|
||||
|
||||
virtual void onDataSignal(const std::string& data) = 0;
|
||||
@@ -41,18 +41,18 @@ protected:
|
||||
public:
|
||||
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize)
|
||||
{
|
||||
m_proxy.callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
|
||||
proxy_->callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
|
||||
}
|
||||
|
||||
std::string concatenateTwoStrings(const std::string& string1, const std::string& string2)
|
||||
{
|
||||
std::string result;
|
||||
m_proxy.callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
|
||||
proxy_->callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
+11
-25
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file server.cpp
|
||||
*
|
||||
@@ -25,13 +24,10 @@
|
||||
*/
|
||||
|
||||
#include "perftests-adaptor.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
@@ -43,24 +39,19 @@ std::string createRandomString(size_t length);
|
||||
class PerftestAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::perftests_adaptor>
|
||||
{
|
||||
public:
|
||||
PerftestAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath objectPath)
|
||||
PerftestAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
PerftestAdaptor(const PerftestAdaptor&) = delete;
|
||||
PerftestAdaptor& operator=(const PerftestAdaptor&) = delete;
|
||||
PerftestAdaptor(PerftestAdaptor&&) = delete;
|
||||
PerftestAdaptor& operator=(PerftestAdaptor&&) = delete;
|
||||
|
||||
~PerftestAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override // NOLINT(bugprone-easily-swappable-parameters)
|
||||
virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override
|
||||
{
|
||||
auto data = createRandomString(signalMsgSize);
|
||||
|
||||
@@ -71,10 +62,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" << '\n';
|
||||
std::cout << "Server sent " << numberOfSignals << " signals in: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop_time - start_time).count() << " ms" << std::endl;
|
||||
}
|
||||
|
||||
std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override
|
||||
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override
|
||||
{
|
||||
return string1 + string2;
|
||||
}
|
||||
@@ -89,13 +80,8 @@ std::string createRandomString(size_t length)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[ random() % max_index ];
|
||||
return charset[ rand() % 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;
|
||||
@@ -105,11 +91,11 @@ std::string createRandomString(size_t length)
|
||||
//-----------------------------------------
|
||||
int main(int /*argc*/, char */*argv*/[])
|
||||
{
|
||||
sdbus::ServiceName const serviceName{"org.sdbuscpp.perftests"};
|
||||
const char* serviceName = "org.sdbuscpp.perftests";
|
||||
auto connection = sdbus::createSystemBusConnection(serviceName);
|
||||
|
||||
sdbus::ObjectPath objectPath{"/org/sdbuscpp/perftests"};
|
||||
PerftestAdaptor server(*connection, std::move(objectPath)); // NOLINT(misc-const-correctness)
|
||||
const char* objectPath = "/org/sdbuscpp/perftests";
|
||||
PerftestAdaptor server(*connection, objectPath);
|
||||
|
||||
connection->enterEventLoop();
|
||||
}
|
||||
|
||||
+5
-5
@@ -22,27 +22,27 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = delete;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = default;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
object_->addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
+5
-5
@@ -22,14 +22,14 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_proxy(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = delete;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = default;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = default;
|
||||
|
||||
~thermometer_proxy() = default;
|
||||
|
||||
@@ -41,12 +41,12 @@ public:
|
||||
uint32_t getCurrentTemperature()
|
||||
{
|
||||
uint32_t result;
|
||||
m_proxy.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
+6
-6
@@ -21,20 +21,20 @@ public:
|
||||
|
||||
protected:
|
||||
concatenator_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
concatenator_adaptor(const concatenator_adaptor&) = delete;
|
||||
concatenator_adaptor& operator=(const concatenator_adaptor&) = delete;
|
||||
concatenator_adaptor(concatenator_adaptor&&) = delete;
|
||||
concatenator_adaptor& operator=(concatenator_adaptor&&) = delete;
|
||||
concatenator_adaptor(concatenator_adaptor&&) = default;
|
||||
concatenator_adaptor& operator=(concatenator_adaptor&&) = default;
|
||||
|
||||
~concatenator_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerMethod("concatenate").withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); })
|
||||
object_->addVTable( sdbus::registerMethod("concatenate").withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); })
|
||||
, sdbus::registerSignal("concatenatedSignal").withParameters<std::string>("concatenatedString")
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
@@ -42,14 +42,14 @@ protected:
|
||||
public:
|
||||
void emitConcatenatedSignal(const std::string& concatenatedString)
|
||||
{
|
||||
m_object.emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
object_->emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
+6
-6
@@ -21,20 +21,20 @@ public:
|
||||
|
||||
protected:
|
||||
concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
concatenator_proxy(const concatenator_proxy&) = delete;
|
||||
concatenator_proxy& operator=(const concatenator_proxy&) = delete;
|
||||
concatenator_proxy(concatenator_proxy&&) = delete;
|
||||
concatenator_proxy& operator=(concatenator_proxy&&) = delete;
|
||||
concatenator_proxy(concatenator_proxy&&) = default;
|
||||
concatenator_proxy& operator=(concatenator_proxy&&) = default;
|
||||
|
||||
~concatenator_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
m_proxy.uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
|
||||
proxy_->uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
|
||||
}
|
||||
|
||||
virtual void onConcatenatedSignal(const std::string& concatenatedString) = 0;
|
||||
@@ -44,11 +44,11 @@ protected:
|
||||
public:
|
||||
sdbus::PendingAsyncCall concatenate(const std::map<std::string, sdbus::Variant>& params)
|
||||
{
|
||||
return m_proxy.callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](std::optional<sdbus::Error> error, const std::string& result){ this->onConcatenateReply(result, std::move(error)); });
|
||||
return proxy_->callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](std::optional<sdbus::Error> error, const std::string& result){ this->onConcatenateReply(result, std::move(error)); });
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
+10
-10
@@ -22,27 +22,27 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = delete;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = default;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
object_->addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
@@ -60,20 +60,20 @@ public:
|
||||
|
||||
protected:
|
||||
factory_adaptor(sdbus::IObject& object)
|
||||
: m_object(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
factory_adaptor(const factory_adaptor&) = delete;
|
||||
factory_adaptor& operator=(const factory_adaptor&) = delete;
|
||||
factory_adaptor(factory_adaptor&&) = delete;
|
||||
factory_adaptor& operator=(factory_adaptor&&) = delete;
|
||||
factory_adaptor(factory_adaptor&&) = default;
|
||||
factory_adaptor& operator=(factory_adaptor&&) = default;
|
||||
|
||||
~factory_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
m_object.addVTable( sdbus::registerMethod("createDelegateObject").withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); })
|
||||
object_->addVTable( sdbus::registerMethod("createDelegateObject").withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); })
|
||||
, sdbus::registerMethod("destroyDelegateObject").withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply()
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& result, sdbus::ObjectPath delegate) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& m_object;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
+11
-11
@@ -22,14 +22,14 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_proxy(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = delete;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = default;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = default;
|
||||
|
||||
~thermometer_proxy() = default;
|
||||
|
||||
@@ -41,12 +41,12 @@ public:
|
||||
uint32_t getCurrentTemperature()
|
||||
{
|
||||
uint32_t result;
|
||||
m_proxy.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
@@ -64,14 +64,14 @@ public:
|
||||
|
||||
protected:
|
||||
factory_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
factory_proxy(const factory_proxy&) = delete;
|
||||
factory_proxy& operator=(const factory_proxy&) = delete;
|
||||
factory_proxy(factory_proxy&&) = delete;
|
||||
factory_proxy& operator=(factory_proxy&&) = delete;
|
||||
factory_proxy(factory_proxy&&) = default;
|
||||
factory_proxy& operator=(factory_proxy&&) = default;
|
||||
|
||||
~factory_proxy() = default;
|
||||
|
||||
@@ -83,17 +83,17 @@ public:
|
||||
sdbus::ObjectPath createDelegateObject()
|
||||
{
|
||||
sdbus::ObjectPath result;
|
||||
m_proxy.callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void destroyDelegateObject(const sdbus::ObjectPath& delegate)
|
||||
{
|
||||
m_proxy.callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
|
||||
proxy_->callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file sdbus-c++-stress-tests.cpp
|
||||
*
|
||||
@@ -34,52 +33,42 @@
|
||||
#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;
|
||||
using namespace std::string_literals;
|
||||
|
||||
const sdbus::ServiceName SERVICE_1_BUS_NAME{"org.sdbuscpp.stresstests.service1"};
|
||||
const sdbus::ServiceName SERVICE_2_BUS_NAME{"org.sdbuscpp.stresstests.service2"};
|
||||
const sdbus::ObjectPath CELSIUS_THERMOMETER_OBJECT_PATH{"/org/sdbuscpp/stresstests/celsius/thermometer"};
|
||||
const sdbus::ObjectPath FAHRENHEIT_THERMOMETER_OBJECT_PATH{"/org/sdbuscpp/stresstests/fahrenheit/thermometer"};
|
||||
const sdbus::ObjectPath CONCATENATOR_OBJECT_PATH{"/org/sdbuscpp/stresstests/concatenator"};
|
||||
#define SERVICE_1_BUS_NAME "org.sdbuscpp.stresstests.service1"s
|
||||
#define SERVICE_2_BUS_NAME "org.sdbuscpp.stresstests.service2"s
|
||||
#define CELSIUS_THERMOMETER_OBJECT_PATH "/org/sdbuscpp/stresstests/celsius/thermometer"s
|
||||
#define FAHRENHEIT_THERMOMETER_OBJECT_PATH "/org/sdbuscpp/stresstests/fahrenheit/thermometer"s
|
||||
#define CONCATENATOR_OBJECT_PATH "/org/sdbuscpp/stresstests/concatenator"s
|
||||
|
||||
class CelsiusThermometerAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_adaptor>
|
||||
{
|
||||
public:
|
||||
CelsiusThermometerAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath objectPath)
|
||||
CelsiusThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
CelsiusThermometerAdaptor(const CelsiusThermometerAdaptor&) = delete;
|
||||
CelsiusThermometerAdaptor& operator=(const CelsiusThermometerAdaptor&) = delete;
|
||||
CelsiusThermometerAdaptor(CelsiusThermometerAdaptor&&) = delete;
|
||||
CelsiusThermometerAdaptor& operator=(CelsiusThermometerAdaptor&&) = delete;
|
||||
|
||||
~CelsiusThermometerAdaptor()
|
||||
{
|
||||
unregisterAdaptor();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t getCurrentTemperature() override
|
||||
virtual uint32_t getCurrentTemperature() override
|
||||
{
|
||||
return m_currentTemperature++;
|
||||
}
|
||||
@@ -91,17 +80,12 @@ private:
|
||||
class CelsiusThermometerProxy : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_proxy>
|
||||
{
|
||||
public:
|
||||
CelsiusThermometerProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath objectPath)
|
||||
CelsiusThermometerProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
CelsiusThermometerProxy(const CelsiusThermometerProxy&) = delete;
|
||||
CelsiusThermometerProxy& operator=(const CelsiusThermometerProxy&) = delete;
|
||||
CelsiusThermometerProxy(CelsiusThermometerProxy&&) = delete;
|
||||
CelsiusThermometerProxy& operator=(CelsiusThermometerProxy&&) = delete;
|
||||
|
||||
~CelsiusThermometerProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
@@ -112,7 +96,7 @@ class FahrenheitThermometerAdaptor final : public sdbus::AdaptorInterfaces< org:
|
||||
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_adaptor >
|
||||
{
|
||||
public:
|
||||
FahrenheitThermometerAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath objectPath, bool isDelegate)
|
||||
FahrenheitThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath, bool isDelegate)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
, celsiusProxy_(connection, SERVICE_2_BUS_NAME, CELSIUS_THERMOMETER_OBJECT_PATH)
|
||||
{
|
||||
@@ -143,7 +127,7 @@ public:
|
||||
{
|
||||
// Create new delegate object
|
||||
auto& connection = getObject().getConnection();
|
||||
sdbus::ObjectPath newObjectPath{FAHRENHEIT_THERMOMETER_OBJECT_PATH + "/" + std::to_string(request.objectNr)};
|
||||
sdbus::ObjectPath newObjectPath = FAHRENHEIT_THERMOMETER_OBJECT_PATH + "/" + std::to_string(request.objectNr);
|
||||
|
||||
// Here we are testing dynamic creation of a D-Bus object in an async way
|
||||
auto adaptor = std::make_unique<FahrenheitThermometerAdaptor>(connection, newObjectPath, true);
|
||||
@@ -158,7 +142,7 @@ public:
|
||||
{
|
||||
// Destroy existing delegate object
|
||||
// Here we are testing dynamic removal of a D-Bus object in an async way
|
||||
const std::lock_guard lock{childrenMutex_};
|
||||
std::lock_guard<std::mutex> lock{childrenMutex_};
|
||||
children_.erase(request.delegateObjectPath);
|
||||
}
|
||||
}
|
||||
@@ -168,11 +152,6 @@ public:
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
FahrenheitThermometerAdaptor(const FahrenheitThermometerAdaptor&) = delete;
|
||||
FahrenheitThermometerAdaptor& operator=(const FahrenheitThermometerAdaptor&) = delete;
|
||||
FahrenheitThermometerAdaptor(FahrenheitThermometerAdaptor&&) = delete;
|
||||
FahrenheitThermometerAdaptor& operator=(FahrenheitThermometerAdaptor&&) = delete;
|
||||
|
||||
~FahrenheitThermometerAdaptor()
|
||||
{
|
||||
exit_ = true;
|
||||
@@ -184,24 +163,24 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t getCurrentTemperature() override
|
||||
virtual 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.);
|
||||
}
|
||||
|
||||
void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) override
|
||||
virtual void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) override
|
||||
{
|
||||
static size_t objectCounter{};
|
||||
objectCounter++;
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
requests_.push(WorkItem{objectCounter, {}, std::move(result)});
|
||||
requests_.push(WorkItem{objectCounter, std::string{}, std::move(result)});
|
||||
lock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
void destroyDelegateObject(sdbus::Result<>&& /*result*/, sdbus::ObjectPath delegate) override
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& /*result*/, sdbus::ObjectPath delegate) override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
requests_.push(WorkItem{0, std::move(delegate), {}});
|
||||
@@ -211,7 +190,7 @@ protected:
|
||||
|
||||
private:
|
||||
CelsiusThermometerProxy celsiusProxy_;
|
||||
std::map<sdbus::ObjectPath, std::unique_ptr<FahrenheitThermometerAdaptor>> children_;
|
||||
std::map<std::string, std::unique_ptr<FahrenheitThermometerAdaptor>> children_;
|
||||
std::mutex childrenMutex_;
|
||||
|
||||
struct WorkItem
|
||||
@@ -224,24 +203,19 @@ 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
|
||||
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_proxy >
|
||||
{
|
||||
public:
|
||||
FahrenheitThermometerProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath objectPath)
|
||||
FahrenheitThermometerProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
FahrenheitThermometerProxy(const FahrenheitThermometerProxy&) = delete;
|
||||
FahrenheitThermometerProxy& operator=(const FahrenheitThermometerProxy&) = delete;
|
||||
FahrenheitThermometerProxy(FahrenheitThermometerProxy&&) = delete;
|
||||
FahrenheitThermometerProxy& operator=(FahrenheitThermometerProxy&&) = delete;
|
||||
|
||||
~FahrenheitThermometerProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
@@ -251,7 +225,7 @@ public:
|
||||
class ConcatenatorAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::concatenator_adaptor>
|
||||
{
|
||||
public:
|
||||
ConcatenatorAdaptor(sdbus::IConnection& connection, sdbus::ObjectPath objectPath)
|
||||
ConcatenatorAdaptor(sdbus::IConnection& connection, std::string objectPath)
|
||||
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||
{
|
||||
unsigned int workers = std::thread::hardware_concurrency();
|
||||
@@ -288,11 +262,6 @@ public:
|
||||
registerAdaptor();
|
||||
}
|
||||
|
||||
ConcatenatorAdaptor(const ConcatenatorAdaptor&) = delete;
|
||||
ConcatenatorAdaptor& operator=(const ConcatenatorAdaptor&) = delete;
|
||||
ConcatenatorAdaptor(ConcatenatorAdaptor&&) = delete;
|
||||
ConcatenatorAdaptor& operator=(ConcatenatorAdaptor&&) = delete;
|
||||
|
||||
~ConcatenatorAdaptor()
|
||||
{
|
||||
exit_ = true;
|
||||
@@ -304,7 +273,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) override
|
||||
virtual 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)});
|
||||
@@ -322,30 +291,25 @@ 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>
|
||||
{
|
||||
public:
|
||||
ConcatenatorProxy(sdbus::IConnection& connection, sdbus::ServiceName destination, sdbus::ObjectPath objectPath)
|
||||
ConcatenatorProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
ConcatenatorProxy(const ConcatenatorProxy&) = delete;
|
||||
ConcatenatorProxy& operator=(const ConcatenatorProxy&) = delete;
|
||||
ConcatenatorProxy(ConcatenatorProxy&&) = delete;
|
||||
ConcatenatorProxy& operator=(ConcatenatorProxy&&) = delete;
|
||||
|
||||
~ConcatenatorProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
private:
|
||||
void onConcatenateReply(const std::string& result, [[maybe_unused]] std::optional<sdbus::Error> error) override
|
||||
virtual void onConcatenateReply(const std::string& result, [[maybe_unused]] std::optional<sdbus::Error> error) override
|
||||
{
|
||||
assert(error == std::nullopt);
|
||||
|
||||
@@ -354,21 +318,21 @@ private:
|
||||
str >> aString;
|
||||
assert(aString == "sdbus-c++-stress-tests");
|
||||
|
||||
uint32_t aNumber{};
|
||||
uint32_t aNumber;
|
||||
str >> aNumber;
|
||||
assert(aNumber > 0);
|
||||
|
||||
++repliesReceived_;
|
||||
}
|
||||
|
||||
void onConcatenatedSignal(const std::string& concatenatedString) override
|
||||
virtual 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);
|
||||
|
||||
@@ -376,15 +340,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[]) // NOLINT(bugprone-exception-escape, readability-function-cognitive-complexity)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
long loops{};
|
||||
long loopDuration{};
|
||||
long loops;
|
||||
long loopDuration;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
@@ -393,52 +357,49 @@ int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape, readabilit
|
||||
}
|
||||
else if (argc == 3)
|
||||
{
|
||||
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)
|
||||
loops = std::atol(argv[1]);
|
||||
loopDuration = std::atol(argv[2]);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Wrong program options");
|
||||
|
||||
std::cout << "Going on with " << loops << " loops and " << loopDuration << "ms loop duration\n";
|
||||
std::cout << "Going on with " << loops << " loops and " << loopDuration << "ms loop duration" << std::endl;
|
||||
|
||||
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 exitLogger{false};
|
||||
std::atomic<bool> exitLogger{};
|
||||
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.\n";
|
||||
std::cout << "Made " << thermometerCallsMade << " thermometer calls so far.\n\n";
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
for (long loop = 0; loop < loops; ++loop)
|
||||
{
|
||||
std::cout << "Entering loop " << loop+1 << '\n';
|
||||
std::cout << "Entering loop " << loop+1 << std::endl;
|
||||
|
||||
auto service2Connection = sdbus::createSystemBusConnection(SERVICE_2_BUS_NAME);
|
||||
std::atomic service2ThreadReady{false};
|
||||
std::atomic<bool> service2ThreadReady{};
|
||||
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 service1ThreadReady{false};
|
||||
std::atomic<bool> service1ThreadReady{};
|
||||
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();
|
||||
@@ -454,7 +415,7 @@ int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape, readabilit
|
||||
bool clientThreadExit{};
|
||||
std::thread clientThread([&, &con = *clientConnection]()
|
||||
{
|
||||
std::atomic stopClients{false};
|
||||
std::atomic<bool> stopClients{false};
|
||||
|
||||
std::thread concatenatorThread([&]()
|
||||
{
|
||||
@@ -481,8 +442,8 @@ int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape, readabilit
|
||||
|
||||
// Update statistics
|
||||
concatenationCallsMade = localCounter;
|
||||
concatenationRepliesReceived = static_cast<uint32_t>(concatenator.repliesReceived_);
|
||||
concatenationSignalsReceived = static_cast<uint32_t>(concatenator.signalsReceived_);
|
||||
concatenationRepliesReceived = (uint32_t)concatenator.repliesReceived_;
|
||||
concatenationSignalsReceived = (uint32_t)concatenator.signalsReceived_;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Connection_test.cpp
|
||||
* @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
|
||||
@@ -26,16 +26,9 @@
|
||||
*/
|
||||
|
||||
#include "Connection.h"
|
||||
#include "sdbus-c++/Error.h"
|
||||
#include "sdbus-c++/Types.h"
|
||||
#include "mocks/SdBusMock.h"
|
||||
#include "unittests/mocks/SdBusMock.h"
|
||||
|
||||
#include <gtest/gtest.h> // IWYU pragma: export
|
||||
#include <cerrno>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::DoAll;
|
||||
@@ -186,10 +179,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()
|
||||
{
|
||||
@@ -200,32 +193,26 @@ 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");
|
||||
}
|
||||
|
||||
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
|
||||
>;
|
||||
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;
|
||||
|
||||
TYPED_TEST_SUITE(AConnectionNameRequest, BusTypeTags);
|
||||
} // namespace
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnectionNameRequest, DoesNotThrowOnSuccess)
|
||||
{
|
||||
EXPECT_CALL(*this->sdBusIntfMock_, sd_bus_request_name(_, _, _)).WillOnce(Return(1));
|
||||
const sdbus::ConnectionName name{"org.sdbuscpp.somename"};
|
||||
|
||||
this->con_->requestName(name);
|
||||
this->con_->requestName("org.sdbuscpp.somename");
|
||||
}
|
||||
|
||||
TYPED_TEST(AConnectionNameRequest, ThrowsOnFail)
|
||||
{
|
||||
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);
|
||||
ASSERT_THROW(this->con_->requestName("org.sdbuscpp.somename"), 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 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Message_test.cpp
|
||||
*
|
||||
@@ -24,28 +24,16 @@
|
||||
* 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 <sdbus-c++/TypeTraits.h>
|
||||
#include "MessageUtils.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::IsNull;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::DoubleEq;
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace
|
||||
@@ -56,15 +44,14 @@ 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(sdbus::signature_of<_ElementType>::str());
|
||||
|
||||
for (const auto& item : items)
|
||||
msg << item;
|
||||
@@ -74,15 +61,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(sdbus::signature_of<_ElementType>::str()))
|
||||
return msg;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ElementType elem;
|
||||
_ElementType elem;
|
||||
if (msg >> elem)
|
||||
items.emplace_back(std::move(elem));
|
||||
else
|
||||
@@ -96,59 +83,44 @@ 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 : std::uint8_t
|
||||
{
|
||||
Value1,
|
||||
Value2,
|
||||
Value3
|
||||
};
|
||||
|
||||
struct Struct
|
||||
{
|
||||
int i{};
|
||||
int i;
|
||||
std::string s;
|
||||
std::list<double> l;
|
||||
Enum e{};
|
||||
|
||||
friend bool operator==(const Struct& lhs, const Struct& rhs) = default;
|
||||
};
|
||||
|
||||
struct RelaxedStruct
|
||||
bool operator==(const Struct& lhs, const Struct& rhs)
|
||||
{
|
||||
int i{};
|
||||
std::string s;
|
||||
std::list<double> l;
|
||||
Enum e{};
|
||||
return lhs.i == rhs.i && lhs.s == rhs.s && lhs.l == rhs.l;
|
||||
}
|
||||
|
||||
friend bool operator==(const RelaxedStruct& lhs, const RelaxedStruct& rhs) = default;
|
||||
};
|
||||
|
||||
struct NestedStruct
|
||||
sdbus::Message& operator<<(sdbus::Message& msg, const Struct& items)
|
||||
{
|
||||
int i{};
|
||||
std::string s;
|
||||
Enum e{};
|
||||
Struct x;
|
||||
return msg << sdbus::Struct{std::forward_as_tuple(items.i, items.s, items.l)};
|
||||
}
|
||||
|
||||
friend bool operator==(const NestedStruct& lhs, const NestedStruct& rhs) = default;
|
||||
};
|
||||
} // namespace my
|
||||
sdbus::Message& operator>>(sdbus::Message& msg, Struct& items)
|
||||
{
|
||||
sdbus::Struct s{std::forward_as_tuple(items.i, items.s, items.l)};
|
||||
return msg >> s;
|
||||
}
|
||||
|
||||
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); // NOLINT(readability-identifier-length)
|
||||
|
||||
SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(my::NestedStruct);
|
||||
SDBUSCPP_REGISTER_STRUCT(my::NestedStruct, i, s, e, x); // NOLINT(readability-identifier-length)
|
||||
template <>
|
||||
struct sdbus::signature_of<my::Struct>
|
||||
: sdbus::signature_of<sdbus::Struct<int, std::string, std::list<double>>>
|
||||
{};
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
@@ -161,7 +133,7 @@ TEST(AMessage, CanBeDefaultConstructed)
|
||||
|
||||
TEST(AMessage, IsInvalidAfterDefaultConstructed)
|
||||
{
|
||||
const sdbus::PlainMessage msg;
|
||||
sdbus::PlainMessage msg;
|
||||
|
||||
ASSERT_FALSE(msg.isValid());
|
||||
}
|
||||
@@ -226,22 +198,7 @@ TEST(AMessage, CanCarryASimpleInteger)
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
int dataRead{};
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryAStringAsAStringView)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::string_view dataWritten = "Hello";
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::string dataRead;
|
||||
int dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
@@ -266,7 +223,7 @@ TEST(AMessage, CanCarryAVariant)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const auto dataWritten = sdbus::Variant(3.14);
|
||||
const auto dataWritten = sdbus::Variant((double)3.14);
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -281,7 +238,7 @@ TEST(AMessage, CanCarryACollectionOfEmbeddedVariants)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
std::vector<sdbus::Variant> value{sdbus::Variant{"hello"s}, sdbus::Variant{3.14}};
|
||||
std::vector<sdbus::Variant> value{sdbus::Variant{"hello"s}, sdbus::Variant{(double)3.14}};
|
||||
const auto dataWritten = sdbus::Variant{value};
|
||||
|
||||
msg << dataWritten;
|
||||
@@ -313,7 +270,7 @@ TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdVector)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::vector dataWritten{sdbus::Signature{"s"}, sdbus::Signature{"u"}, sdbus::Signature{"b"}};
|
||||
const std::vector<sdbus::Signature> dataWritten{"s", "u", "b"};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -328,12 +285,12 @@ TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdArray)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::array dataWritten{3545342, 43643532, 324325};
|
||||
const std::array<int, 3> 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));
|
||||
@@ -343,7 +300,7 @@ TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdArray)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::array dataWritten{sdbus::Signature{"s"}, sdbus::Signature{"u"}, sdbus::Signature{"b"}};
|
||||
const std::array<sdbus::Signature, 3> dataWritten{"s", "u", "b"};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -354,18 +311,18 @@ TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdArray)
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
#if __cplusplus >= 202002L
|
||||
TEST(AMessage, CanCarryDBusArrayOfTrivialTypesGivenAsStdSpan)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::array sourceArray{3545342, 43643532, 324325};
|
||||
const std::array<int, 3> 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;
|
||||
|
||||
@@ -376,7 +333,7 @@ TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdSpan)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::array sourceArray{sdbus::Signature{"s"}, sdbus::Signature{"u"}, sdbus::Signature{"b"}};
|
||||
const std::array<sdbus::Signature, 3> sourceArray{"s", "u", "b"};
|
||||
const std::span dataWritten{sourceArray};
|
||||
|
||||
msg << dataWritten;
|
||||
@@ -390,24 +347,6 @@ TEST(AMessage, CanCarryDBusArrayOfNontrivialTypesGivenAsStdSpan)
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AMessage, CanCarryAnEnumValue)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
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();
|
||||
|
||||
EnumA aRead{};
|
||||
EnumB bRead{};
|
||||
msg >> aRead >> bRead;
|
||||
|
||||
ASSERT_THAT(aRead, Eq(aWritten));
|
||||
ASSERT_THAT(bRead, Eq(bWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, ThrowsWhenDestinationStdArrayIsTooSmallDuringDeserialization)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
@@ -417,11 +356,11 @@ TEST(AMessage, ThrowsWhenDestinationStdArrayIsTooSmallDuringDeserialization)
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::array<int, 3> dataRead{};
|
||||
std::array<int, 3> dataRead;
|
||||
ASSERT_THROW(msg >> dataRead, sdbus::Error);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
#if __cplusplus >= 202002L
|
||||
TEST(AMessage, ThrowsWhenDestinationStdSpanIsTooSmallDuringDeserialization)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
@@ -431,7 +370,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);
|
||||
}
|
||||
@@ -441,7 +380,7 @@ TEST(AMessage, CanCarryADictionary)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::map<int, std::string> dataWritten{{1, "one"}, {2, "two"}};
|
||||
std::map<int, std::string> dataWritten{{1, "one"}, {2, "two"}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -476,7 +415,7 @@ TEST(AMessage, CanCarryAComplexType)
|
||||
>
|
||||
>;
|
||||
|
||||
const ComplexType dataWritten = { {1, {{{5, {{sdbus::ObjectPath{"/some/object"}, true, 45, {{6, "hello"}, {7, "world"}}}}}}, sdbus::Signature{"av"}, 3.14}}};
|
||||
ComplexType dataWritten = { {1, {{{5, {{"/some/object", true, 45, {{6, "hello"}, {7, "world"}}}}}}, "av", 3.14}}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -493,10 +432,11 @@ TEST(AMessage, CanPeekASimpleType)
|
||||
msg << 123;
|
||||
msg.seal();
|
||||
|
||||
auto [type, contents] = msg.peekType();
|
||||
|
||||
ASSERT_THAT(type, Eq('i'));
|
||||
ASSERT_THAT(contents, IsNull());
|
||||
std::string type;
|
||||
std::string contents;
|
||||
msg.peekType(type, contents);
|
||||
ASSERT_THAT(type, "i");
|
||||
ASSERT_THAT(contents, "");
|
||||
}
|
||||
|
||||
TEST(AMessage, CanPeekContainerContents)
|
||||
@@ -505,10 +445,11 @@ TEST(AMessage, CanPeekContainerContents)
|
||||
msg << std::map<int, std::string>{{1, "one"}, {2, "two"}};
|
||||
msg.seal();
|
||||
|
||||
auto [type, contents] = msg.peekType();
|
||||
|
||||
ASSERT_THAT(type, Eq('a'));
|
||||
ASSERT_THAT(contents, StrEq("{is}"));
|
||||
std::string type;
|
||||
std::string contents;
|
||||
msg.peekType(type, contents);
|
||||
ASSERT_THAT(type, "a");
|
||||
ASSERT_THAT(contents, "{is}");
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryDBusArrayGivenAsCustomType)
|
||||
@@ -528,11 +469,11 @@ TEST(AMessage, CanCarryDBusArrayGivenAsCustomType)
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryUserDefinedStruct)
|
||||
TEST(AMessage, CanCarryDBusStructGivenAsCustomType)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const my::Struct dataWritten{3545342, "hello"s, {3.14, 2.4568546}, my::Enum::Value2};
|
||||
const my::Struct dataWritten{3545342, "hello"s, {3.14, 2.4568546}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
@@ -542,149 +483,3 @@ TEST(AMessage, CanCarryUserDefinedStruct)
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanCarryNestedUserDefinedStruct)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const my::NestedStruct dataWritten{3545342, "hello"s, my::Enum::Value2, {12, "world"s, {3.14, 2.4568546}, my::Enum::Value3}};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
my::NestedStruct dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanSerializeUserDefinedStructAsDictionaryOfStringsToVariants)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const my::Struct dataWritten{3545342, "hello"s, {3.14, 2.4568546}, my::Enum::Value2};
|
||||
|
||||
msg << sdbus::as_dictionary{dataWritten};
|
||||
msg.seal();
|
||||
|
||||
std::map<std::string, sdbus::Variant> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, SizeIs(4));
|
||||
ASSERT_THAT(dataRead.at("i").get<int>(), Eq(3545342));
|
||||
ASSERT_THAT(dataRead.at("s").get<std::string>(), Eq("hello"));
|
||||
ASSERT_THAT(dataRead.at("l").get<std::list<double>>(), ElementsAre(3.14, 2.4568546));
|
||||
ASSERT_THAT(dataRead.at("e").get<my::Enum>(), Eq(my::Enum::Value2));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanRecursivelySerializeUserDefinedStructAsDictionaryOfStringsToVariants)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const my::NestedStruct dataWritten{3545342, "hello"s, my::Enum::Value2, {12, "world"s, {3.14, 2.4568546}, my::Enum::Value3}};
|
||||
|
||||
msg << sdbus::as_dictionary{dataWritten};
|
||||
msg.seal();
|
||||
|
||||
std::map<std::string, sdbus::Variant> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, SizeIs(4));
|
||||
ASSERT_THAT(dataRead.at("i").get<int>(), Eq(3545342));
|
||||
ASSERT_THAT(dataRead.at("s").get<std::string>(), Eq("hello"));
|
||||
ASSERT_THAT(dataRead.at("e").get<my::Enum>(), Eq(my::Enum::Value2));
|
||||
auto nestedStructRead = dataRead.at("x").get<std::map<std::string, sdbus::Variant>>(); // Nested struct serialized as dict
|
||||
ASSERT_THAT(nestedStructRead.at("i").get<int>(), Eq(12));
|
||||
ASSERT_THAT(nestedStructRead.at("s").get<std::string>(), Eq("world"));
|
||||
ASSERT_THAT(nestedStructRead.at("l").get<std::list<double>>(), ElementsAre(3.14, 2.4568546));
|
||||
ASSERT_THAT(nestedStructRead.at("e").get<my::Enum>(), Eq(my::Enum::Value3));
|
||||
}
|
||||
|
||||
TEST(AMessage, CanDeserializeDictionaryOfStringsToVariantsIntoUserDefinedStruct)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
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();
|
||||
|
||||
my::Struct dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(my::Struct{3545342, "hello"s, {3.14, 2.4568546}, my::Enum::Value2}));
|
||||
}
|
||||
|
||||
TEST(AMessage, FailsDeserializingDictionaryIntoUserDefinedStructIfStructMemberIsNotFound)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
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();
|
||||
|
||||
my::Struct dataRead;
|
||||
|
||||
ASSERT_THROW(msg >> dataRead, sdbus::Error);
|
||||
}
|
||||
|
||||
TEST(AMessage, DeserializesDictionaryIntoStructWithMissingMembersSuccessfullyIfRelaxedOptionIsSet)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
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();
|
||||
|
||||
my::RelaxedStruct dataRead{};
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(my::RelaxedStruct{{}, {}, {3.14, 2.4568546}, my::Enum::Value2}));
|
||||
}
|
||||
|
||||
class AMessage : public ::testing::TestWithParam<std::variant<int32_t, std::string, my::Struct>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(AMessage, CanCarryDBusVariantGivenAsStdVariant)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::variant<int32_t, std::string, my::Struct> dataWritten{GetParam()};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::variant<int32_t, std::string, my::Struct> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST_P(AMessage, ThrowsWhenDestinationStdVariantHasWrongTypeDuringDeserialization)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::variant<int32_t, std::string, my::Struct> dataWritten{GetParam()};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::variant<std::vector<bool>> dataRead;
|
||||
ASSERT_THROW(msg >> dataRead, sdbus::Error);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P( StringIntStruct
|
||||
, AMessage
|
||||
, ::testing::Values("hello"s, 1, my::Struct{}));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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 pollData{};
|
||||
pollData.timeout = std::chrono::microseconds::zero();
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::zero();
|
||||
|
||||
auto relativeTimeout = pollData.getRelativeTimeout();
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::zero()));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroPollTimeoutForZeroAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
pollData.timeout = std::chrono::microseconds::zero();
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::zero();
|
||||
|
||||
auto pollTimeout = pollData.getPollTimeout();
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(0));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsInfiniteRelativeTimeoutForInfiniteAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
pollData.timeout = std::chrono::microseconds::max();
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::max();
|
||||
|
||||
auto relativeTimeout = pollData.getRelativeTimeout();
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(std::chrono::microseconds::max()));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsNegativePollTimeoutForInfiniteAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
pollData.timeout = std::chrono::microseconds::max();
|
||||
sdbus::IConnection::PollData pd;
|
||||
pd.timeout = std::chrono::microseconds::max();
|
||||
|
||||
auto pollTimeout = pollData.getPollTimeout();
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(-1));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroRelativeTimeoutForPastAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto past = std::chrono::steady_clock::now() - 10s;
|
||||
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
|
||||
auto relativeTimeout = pollData.getRelativeTimeout();
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, Eq(0us));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsZeroPollTimeoutForPastAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto past = std::chrono::steady_clock::now() - 10s;
|
||||
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(past.time_since_epoch());
|
||||
|
||||
auto pollTimeout = pollData.getPollTimeout();
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, Eq(0));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsCorrectRelativeTimeoutForFutureAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto future = std::chrono::steady_clock::now() + 1s;
|
||||
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
|
||||
auto relativeTimeout = pollData.getRelativeTimeout();
|
||||
auto relativeTimeout = pd.getRelativeTimeout();
|
||||
|
||||
EXPECT_THAT(relativeTimeout, AllOf(Ge(900ms), Le(1100ms)));
|
||||
}
|
||||
|
||||
TEST(PollData, ReturnsCorrectPollTimeoutForFutureAbsoluteTimeout)
|
||||
{
|
||||
sdbus::IConnection::PollData pollData{};
|
||||
sdbus::IConnection::PollData pd;
|
||||
auto future = std::chrono::steady_clock::now() + 1s;
|
||||
pollData.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
pd.timeout = std::chrono::duration_cast<std::chrono::microseconds>(future.time_since_epoch());
|
||||
|
||||
auto pollTimeout = pollData.getPollTimeout();
|
||||
auto pollTimeout = pd.getPollTimeout();
|
||||
|
||||
EXPECT_THAT(pollTimeout, AllOf(Ge(900), Le(1100)));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file TypeTraits_test.cpp
|
||||
*
|
||||
@@ -30,15 +30,6 @@
|
||||
#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;
|
||||
|
||||
@@ -48,37 +39,20 @@ namespace
|
||||
// FIXTURE DEFINITION FOR TYPED TESTS
|
||||
// ----
|
||||
|
||||
template <typename>
|
||||
template <typename _T>
|
||||
class Type2DBusTypeSignatureConversion
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
std::string dbusTypeSignature_{getDBusTypeSignature()};
|
||||
const std::string dbusTypeSignature_{getDBusTypeSignature()};
|
||||
private:
|
||||
static std::string getDBusTypeSignature();
|
||||
};
|
||||
|
||||
enum class SomeEnumClass : uint8_t
|
||||
{
|
||||
A, B, C
|
||||
};
|
||||
|
||||
enum struct SomeEnumStruct : int64_t // NOLINT(performance-enum-size)
|
||||
{
|
||||
A, B, C
|
||||
};
|
||||
|
||||
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); \
|
||||
@@ -96,28 +70,17 @@ namespace
|
||||
TYPE(double)HAS_DBUS_TYPE_SIGNATURE("d")
|
||||
TYPE(const char*)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(std::string)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(std::string_view)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(sdbus::BusName)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(sdbus::InterfaceName)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(sdbus::MemberName)HAS_DBUS_TYPE_SIGNATURE("s")
|
||||
TYPE(sdbus::ObjectPath)HAS_DBUS_TYPE_SIGNATURE("o")
|
||||
TYPE(sdbus::Signature)HAS_DBUS_TYPE_SIGNATURE("g")
|
||||
TYPE(sdbus::Variant)HAS_DBUS_TYPE_SIGNATURE("v")
|
||||
TYPE(std::variant<int16_t, std::string>)HAS_DBUS_TYPE_SIGNATURE("v")
|
||||
TYPE(sdbus::UnixFd)HAS_DBUS_TYPE_SIGNATURE("h")
|
||||
TYPE(sdbus::Struct<bool>)HAS_DBUS_TYPE_SIGNATURE("(b)")
|
||||
TYPE(sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>)HAS_DBUS_TYPE_SIGNATURE("(qdsv)")
|
||||
TYPE(std::vector<int16_t>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
TYPE(std::array<int16_t, 3>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
#ifdef __cpp_lib_span
|
||||
TYPE(std::span<int16_t>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
#if __cplusplus >= 202002L
|
||||
TYPE(std::span<int16_t>)HAS_DBUS_TYPE_SIGNATURE("ao")
|
||||
#endif
|
||||
TYPE(SomeEnumClass)HAS_DBUS_TYPE_SIGNATURE("y")
|
||||
TYPE(const SomeEnumClass)HAS_DBUS_TYPE_SIGNATURE("y")
|
||||
TYPE(volatile SomeEnumClass)HAS_DBUS_TYPE_SIGNATURE("y")
|
||||
TYPE(const volatile SomeEnumClass)HAS_DBUS_TYPE_SIGNATURE("y")
|
||||
TYPE(SomeEnumStruct)HAS_DBUS_TYPE_SIGNATURE("x")
|
||||
TYPE(SomeClassicEnum)HAS_DBUS_TYPE_SIGNATURE("u")
|
||||
TYPE(std::map<int32_t, int64_t>)HAS_DBUS_TYPE_SIGNATURE("a{ix}")
|
||||
TYPE(std::unordered_map<int32_t, int64_t>)HAS_DBUS_TYPE_SIGNATURE("a{ix}")
|
||||
using ComplexType = std::map<
|
||||
@@ -137,51 +100,40 @@ namespace
|
||||
>,
|
||||
sdbus::Signature,
|
||||
sdbus::UnixFd,
|
||||
const char*,
|
||||
std::string_view
|
||||
const char*
|
||||
>
|
||||
>;
|
||||
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(oanbva{is})}ghss)}")
|
||||
TYPE(ComplexType)HAS_DBUS_TYPE_SIGNATURE("a{t(a{ya(oanbva{is})}ghs)}")
|
||||
|
||||
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>
|
||||
typedef ::testing::Types< bool
|
||||
, uint8_t
|
||||
, int16_t
|
||||
, uint16_t
|
||||
, int32_t
|
||||
, uint32_t
|
||||
, int64_t
|
||||
, uint64_t
|
||||
, double
|
||||
, const char*
|
||||
, std::string
|
||||
, sdbus::ObjectPath
|
||||
, sdbus::Signature
|
||||
, sdbus::Variant
|
||||
, sdbus::UnixFd
|
||||
, sdbus::Struct<bool>
|
||||
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
|
||||
, std::vector<int16_t>
|
||||
, std::array<int16_t, 3>
|
||||
#if __cplusplus >= 202002L
|
||||
, 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 >;
|
||||
, std::map<int32_t, int64_t>
|
||||
, std::unordered_map<int32_t, int64_t>
|
||||
, ComplexType
|
||||
> DBusSupportedTypes;
|
||||
|
||||
TYPED_TEST_SUITE(Type2DBusTypeSignatureConversion, DBusSupportedTypes);
|
||||
} // namespace
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
/* -- TEST CASES -- */
|
||||
@@ -189,8 +141,7 @@ namespace
|
||||
|
||||
TYPED_TEST(Type2DBusTypeSignatureConversion, ConvertsTypeToProperDBusSignature)
|
||||
{
|
||||
constexpr auto signature = sdbus::as_null_terminated(sdbus::signature_of_v<TypeParam>);
|
||||
ASSERT_THAT(signature.data(), Eq(this->dbusTypeSignature_));
|
||||
ASSERT_THAT(sdbus::signature_of<TypeParam>::str(), Eq(this->dbusTypeSignature_));
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfTrivialSignatureFunction)
|
||||
@@ -199,11 +150,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_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(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(sdbus::function_argument_count_v<Fnc> == 0, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_void_v<sdbus::function_result_t<Fnc>>, "Incorrectly detected free function return type");
|
||||
static_assert(std::is_void<sdbus::function_result_t<Fnc>>::value, "Incorrectly detected free function return type");
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfNontrivialSignatureFunction)
|
||||
@@ -212,11 +163,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_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(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(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_same_v<sdbus::function_result_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected free function return type");
|
||||
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
|
||||
}
|
||||
|
||||
TEST(FreeFunctionTypeTraits, DetectsTraitsOfAsyncFunction)
|
||||
@@ -225,9 +176,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_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(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(sdbus::function_argument_count_v<Fnc> == 3, "Incorrectly detected free function parameter count");
|
||||
static_assert(std::is_same_v<sdbus::function_result_t<Fnc>, std::tuple<char, int>>, "Incorrectly detected free function return type");
|
||||
static_assert(std::is_same<sdbus::function_result_t<Fnc>, std::tuple<char, int>>::value, "Incorrectly detected free function return type");
|
||||
}
|
||||
|
||||
+59
-223
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file Types_test.cpp
|
||||
*
|
||||
@@ -24,35 +24,22 @@
|
||||
* 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 <sdbus-c++/TypeTraits.h>
|
||||
|
||||
#include "MessageUtils.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 -- */
|
||||
@@ -65,14 +52,14 @@ TEST(AVariant, CanBeDefaultConstructed)
|
||||
|
||||
TEST(AVariant, ContainsNoValueAfterDefaultConstructed)
|
||||
{
|
||||
const sdbus::Variant var;
|
||||
sdbus::Variant v;
|
||||
|
||||
ASSERT_TRUE(var.isEmpty());
|
||||
ASSERT_TRUE(v.isEmpty());
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeConstructedFromASimpleValue)
|
||||
{
|
||||
const int value = 5;
|
||||
int value = 5;
|
||||
|
||||
ASSERT_NO_THROW(sdbus::Variant{value});
|
||||
}
|
||||
@@ -80,140 +67,53 @@ TEST(AVariant, CanBeConstructedFromASimpleValue)
|
||||
TEST(AVariant, CanBeConstructedFromAComplexValue)
|
||||
{
|
||||
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}}} };
|
||||
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
|
||||
|
||||
ASSERT_NO_THROW(sdbus::Variant{value});
|
||||
}
|
||||
|
||||
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}};
|
||||
const StdVariantType stdVariant{value};
|
||||
|
||||
const sdbus::Variant sdbusVariant{stdVariant};
|
||||
|
||||
ASSERT_TRUE(sdbusVariant.containsValueOfType<ComplexType>());
|
||||
ASSERT_THAT(sdbusVariant.get<ComplexType>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeCopied)
|
||||
{
|
||||
auto value = "hello"s;
|
||||
const sdbus::Variant variant(value);
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
const auto variantCopy1{variant}; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
const auto variantCopy2 = variantCopy1; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
auto variantCopy1{variant};
|
||||
auto variantCopy2 = variantCopy1;
|
||||
|
||||
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)
|
||||
{
|
||||
const sdbus::Variant var("hello");
|
||||
sdbus::Variant v("hello");
|
||||
|
||||
ASSERT_FALSE(var.isEmpty());
|
||||
ASSERT_FALSE(v.isEmpty());
|
||||
}
|
||||
|
||||
TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
|
||||
{
|
||||
const int value = 5;
|
||||
int value = 5;
|
||||
|
||||
const sdbus::Variant variant(value);
|
||||
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>>>;
|
||||
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
|
||||
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
|
||||
|
||||
const sdbus::Variant variant(value);
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_THAT(variant.get<ComplexType>(), Eq(value));
|
||||
ASSERT_THAT(variant.get<decltype(value)>(), 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)
|
||||
{
|
||||
const std::string value{"I am a string"};
|
||||
const sdbus::Variant variant(value);
|
||||
std::string value{"I am a string"};
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_THAT(variant.get<std::string>(), Eq(value));
|
||||
ASSERT_THAT(variant.get<std::string>(), Eq(value));
|
||||
@@ -223,42 +123,18 @@ TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
|
||||
TEST(AVariant, ReturnsTrueWhenAskedIfItContainsTheTypeItReallyContains)
|
||||
{
|
||||
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}}} };
|
||||
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
|
||||
|
||||
const sdbus::Variant variant(value);
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_TRUE(variant.containsValueOfType<ComplexType>());
|
||||
}
|
||||
|
||||
TEST(AVariant, CanBeConvertedIntoAnStdVariant)
|
||||
{
|
||||
using ComplexType = std::vector<sdbus::Struct<std::string, double>>;
|
||||
using StdVariantType = std::variant<std::string, uint64_t, ComplexType>;
|
||||
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));
|
||||
ASSERT_THAT(std::get<ComplexType>(stdVariant), Eq(value));
|
||||
}
|
||||
|
||||
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}};
|
||||
const StdVariantType stdVariant{value};
|
||||
|
||||
auto stdVariantCopy = [](const sdbus::Variant &var) -> StdVariantType { return var; }(stdVariant);
|
||||
|
||||
ASSERT_THAT(stdVariantCopy, Eq(stdVariant));
|
||||
}
|
||||
|
||||
TEST(ASimpleVariant, ReturnsFalseWhenAskedIfItContainsTypeItDoesntReallyContain)
|
||||
{
|
||||
const int value = 5;
|
||||
int value = 5;
|
||||
|
||||
const sdbus::Variant variant(value);
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_FALSE(variant.containsValueOfType<double>());
|
||||
}
|
||||
@@ -267,17 +143,17 @@ TEST(AVariant, CanContainOtherEmbeddedVariants)
|
||||
{
|
||||
using TypeWithVariants = std::vector<sdbus::Struct<sdbus::Variant, double>>;
|
||||
TypeWithVariants value;
|
||||
value.emplace_back(sdbus::Variant("a string"), ANY_DOUBLE);
|
||||
value.emplace_back(sdbus::Variant(ANY_UINT64), ANY_DOUBLE);
|
||||
value.push_back({sdbus::Variant("a string"), ANY_DOUBLE});
|
||||
value.push_back({sdbus::Variant(ANY_UINT64), ANY_DOUBLE});
|
||||
|
||||
const sdbus::Variant variant(value);
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
ASSERT_TRUE(variant.containsValueOfType<TypeWithVariants>());
|
||||
}
|
||||
|
||||
TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
|
||||
{
|
||||
const sdbus::Variant variant("a string");
|
||||
sdbus::Variant variant("a string");
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
@@ -286,7 +162,7 @@ TEST(ANonEmptyVariant, SerializesSuccessfullyToAMessage)
|
||||
|
||||
TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
|
||||
{
|
||||
const sdbus::Variant variant;
|
||||
sdbus::Variant variant;
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
@@ -296,8 +172,8 @@ TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage)
|
||||
TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
|
||||
{
|
||||
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);
|
||||
ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
|
||||
sdbus::Variant variant(value);
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
variant.serializeTo(msg);
|
||||
@@ -305,30 +181,30 @@ TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully)
|
||||
sdbus::Variant variant2;
|
||||
variant2.deserializeFrom(msg);
|
||||
|
||||
ASSERT_THAT(variant2.get<ComplexType>(), Eq(value));
|
||||
ASSERT_THAT(variant2.get<decltype(value)>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
|
||||
{
|
||||
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);
|
||||
auto variantCopy1{variant}; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
auto variantCopy2 = variant; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
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;
|
||||
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
variant.serializeTo(msg);
|
||||
variantCopy1.serializeTo(msg);
|
||||
variantCopy2.serializeTo(msg);
|
||||
msg.seal();
|
||||
sdbus::Variant receivedVariant1, receivedVariant2, receivedVariant3; // NOLINT(readability-isolate-declaration)
|
||||
sdbus::Variant receivedVariant1, receivedVariant2, receivedVariant3;
|
||||
receivedVariant1.deserializeFrom(msg);
|
||||
receivedVariant2.deserializeFrom(msg);
|
||||
receivedVariant3.deserializeFrom(msg);
|
||||
|
||||
ASSERT_THAT(receivedVariant1.get<ComplexType>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant2.get<ComplexType>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant3.get<ComplexType>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant1.get<decltype(value)>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant2.get<decltype(value)>(), Eq(value));
|
||||
ASSERT_THAT(receivedVariant3.get<decltype(value)>(), Eq(value));
|
||||
}
|
||||
|
||||
TEST(AStruct, CanBeCreatedFromStdTuple)
|
||||
@@ -359,7 +235,7 @@ TEST(AStruct, CanBeUsedLikeStdTupleType)
|
||||
|
||||
TEST(AStruct, CanBeUsedInStructuredBinding)
|
||||
{
|
||||
const sdbus::Struct valueStruct(1234, "abcd", true);
|
||||
sdbus::Struct valueStruct(1234, "abcd", true);
|
||||
|
||||
auto [first, second, third] = valueStruct;
|
||||
|
||||
@@ -375,7 +251,7 @@ TEST(AnObjectPath, CanBeConstructedFromCString)
|
||||
|
||||
TEST(AnObjectPath, CanBeConstructedFromStdString)
|
||||
{
|
||||
const std::string aPath{"/some/path"};
|
||||
std::string aPath{"/some/path"};
|
||||
|
||||
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
|
||||
}
|
||||
@@ -386,6 +262,7 @@ 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)
|
||||
@@ -397,7 +274,7 @@ TEST(ASignature, CanBeConstructedFromCString)
|
||||
|
||||
TEST(ASignature, CanBeConstructedFromStdString)
|
||||
{
|
||||
const std::string aSignature{"us"};
|
||||
std::string aSignature{"us"};
|
||||
|
||||
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
|
||||
}
|
||||
@@ -408,6 +285,7 @@ TEST(ASignature, CanBeMovedLikeAStdString)
|
||||
sdbus::Signature oSignature{aSignature};
|
||||
|
||||
ASSERT_THAT(sdbus::Signature{std::move(oSignature)}, Eq(sdbus::Signature(std::move(aSignature))));
|
||||
ASSERT_THAT(std::string(oSignature), Eq(aSignature));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, DuplicatesAndOwnsFdUponStandardConstruction)
|
||||
@@ -428,9 +306,9 @@ TEST(AUnixFd, AdoptsAndOwnsFdAsIsUponAdoptionConstruction)
|
||||
|
||||
TEST(AUnixFd, DuplicatesFdUponCopyConstruction)
|
||||
{
|
||||
const sdbus::UnixFd unixFd(::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK));
|
||||
sdbus::UnixFd unixFd(::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK));
|
||||
|
||||
const sdbus::UnixFd unixFdCopy{unixFd}; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
sdbus::UnixFd unixFdCopy{unixFd};
|
||||
|
||||
EXPECT_THAT(unixFdCopy.get(), Gt(unixFd.get()));
|
||||
}
|
||||
@@ -440,20 +318,20 @@ TEST(AUnixFd, TakesOverFdUponMoveConstruction)
|
||||
auto fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
|
||||
const sdbus::UnixFd unixFdNew{std::move(unixFd)};
|
||||
sdbus::UnixFd unixFdNew{std::move(unixFd)};
|
||||
|
||||
EXPECT_FALSE(unixFd.isValid()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move)
|
||||
EXPECT_FALSE(unixFd.isValid());
|
||||
EXPECT_THAT(unixFdNew.get(), Eq(fd));
|
||||
}
|
||||
|
||||
TEST(AUnixFd, ClosesFdProperlyUponDestruction)
|
||||
{
|
||||
int fd{}, fdCopy{}; // NOLINT(readability-isolate-declaration)
|
||||
int fd, fdCopy;
|
||||
{
|
||||
fd = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
|
||||
sdbus::UnixFd unixFd(fd, sdbus::adopt_fd);
|
||||
auto unixFdNew = std::move(unixFd);
|
||||
auto unixFdCopy = unixFdNew; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
auto unixFdCopy = unixFdNew;
|
||||
fdCopy = unixFdCopy.get();
|
||||
}
|
||||
|
||||
@@ -464,7 +342,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();
|
||||
@@ -513,60 +391,18 @@ TEST(AUnixFd, TakesOverNewFdAndClosesOriginalFdOnAdoptingReset)
|
||||
|
||||
TEST(AnError, CanBeConstructedFromANameAndAMessage)
|
||||
{
|
||||
auto error = sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.error"}, "message");
|
||||
EXPECT_THAT(error.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
auto error = sdbus::Error("name", "message");
|
||||
EXPECT_THAT(error.getName(), Eq<std::string>("name"));
|
||||
EXPECT_THAT(error.getMessage(), Eq<std::string>("message"));
|
||||
EXPECT_TRUE(error.isValid());
|
||||
}
|
||||
|
||||
TEST(AnError, CanBeConstructedFromANameOnly)
|
||||
{
|
||||
auto error1 = sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.error"});
|
||||
auto error2 = sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.error"}, nullptr);
|
||||
EXPECT_THAT(error1.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
EXPECT_THAT(error2.getName(), Eq<std::string>("org.sdbuscpp.error"));
|
||||
auto error1 = sdbus::Error("name");
|
||||
auto error2 = sdbus::Error("name", nullptr);
|
||||
EXPECT_THAT(error1.getName(), Eq<std::string>("name"));
|
||||
EXPECT_THAT(error2.getName(), Eq<std::string>("name"));
|
||||
|
||||
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());
|
||||
EXPECT_THAT(error1.getMessage(), Eq<std::string>(""));
|
||||
EXPECT_THAT(error2.getMessage(), Eq<std::string>(""));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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 *msg));
|
||||
MOCK_METHOD1(sd_bus_message_unref, sd_bus_message*(sd_bus_message *msg));
|
||||
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_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_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_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_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_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,18 +78,17 @@ 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 **ret));
|
||||
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
|
||||
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));
|
||||
MOCK_METHOD2(sd_bus_get_n_queued_read, int(sd_bus *bus, uint64_t *ret));
|
||||
MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
|
||||
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 *msg, const char *destination));
|
||||
MOCK_METHOD2(sd_bus_message_set_destination, int(sd_bus_message *m, 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 *));
|
||||
MOCK_METHOD1(sd_bus_creds_unref, sd_bus_creds*(sd_bus_creds *));
|
||||
|
||||
MOCK_METHOD2(sd_bus_creds_get_pid, int(sd_bus_creds *, pid_t *));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 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.3.0)
|
||||
project(sdbus-c++-tools VERSION 2.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@@ -35,8 +35,7 @@ set(SDBUSCPP_XML2CPP_SRCS
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
unset(CMAKE_CXX_CLANG_TIDY) # Do not propagate clang-tidy to tools
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
#----------------------------------
|
||||
# EXECUTABLE BUILD INFORMATION
|
||||
@@ -45,7 +44,6 @@ unset(CMAKE_CXX_CLANG_TIDY) # Do not propagate clang-tidy to tools
|
||||
add_executable(sdbus-c++-xml2cpp ${SDBUSCPP_XML2CPP_SRCS})
|
||||
target_link_libraries (sdbus-c++-xml2cpp ${EXPAT_LIBRARIES})
|
||||
target_include_directories(sdbus-c++-xml2cpp PRIVATE ${EXPAT_INCLUDE_DIRS})
|
||||
target_compile_definitions(sdbus-c++-xml2cpp PRIVATE SDBUS_XML2CPP_VERSION="${CMAKE_PROJECT_VERSION}")
|
||||
|
||||
#----------------------------------
|
||||
# CMAKE CONFIG & PACKAGE CONFIG
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file AdaptorGenerator.cpp
|
||||
*
|
||||
@@ -85,15 +85,15 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IObject& object)" << endl
|
||||
<< tab << tab << ": m_object(object)" << endl
|
||||
<< tab << tab << ": object_(&object)" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = delete;" << endl << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
@@ -121,7 +121,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
if(!annotationRegistration.empty())
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "sdbus::setInterfaceFlags()" << annotationRegistration;
|
||||
str << "sdbus::setInterfaceFlags()" << annotationRegistration << ";";
|
||||
annotationRegistration = str.str();
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IObject& m_object;" << endl
|
||||
<< tab << "sdbus::IObject* object_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
@@ -303,7 +303,7 @@ std::tuple<std::vector<std::string>, std::string> AdaptorGenerator::processSigna
|
||||
|
||||
signalMethodSS << tab << "void emit" << nameWithCapFirstLetter << "(" << argTypeStr << ")" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << tab << "m_object.emitSignal(\"" << name << "\")"
|
||||
<< tab << tab << "object_->emitSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
|
||||
if (!argStr.empty())
|
||||
@@ -402,11 +402,11 @@ std::string AdaptorGenerator::createVTableRegistration(const std::string& annota
|
||||
std::ostringstream registrationSS;
|
||||
if (allRegistrations.size() == 1)
|
||||
{
|
||||
registrationSS << tab << tab << "m_object.addVTable(" << allRegistrations[0] << ").forInterface(INTERFACE_NAME);";
|
||||
registrationSS << tab << tab << "object_->addVTable(" << allRegistrations[0] << ").forInterface(INTERFACE_NAME);";
|
||||
}
|
||||
else
|
||||
{
|
||||
registrationSS << tab << tab << "m_object.addVTable( " << allRegistrations[0] << endl;
|
||||
registrationSS << tab << tab << "object_->addVTable( " << allRegistrations[0] << endl;
|
||||
for (size_t i = 1; i < allRegistrations.size(); ++i)
|
||||
registrationSS << tab << tab << " , " << allRegistrations[i] << endl;
|
||||
registrationSS << tab << tab << " ).forInterface(INTERFACE_NAME);";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file AdaptorGenerator.h
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file BaseGenerator.cpp
|
||||
*
|
||||
@@ -53,7 +53,7 @@ int BaseGenerator::transformXmlToFile(const Document& doc, const char* filename)
|
||||
int BaseGenerator::writeToFile(const char* filename, const std::string& data) const
|
||||
{
|
||||
std::ofstream file(filename);
|
||||
if (file.fail())
|
||||
if (file.bad())
|
||||
{
|
||||
std::cerr << "Unable to write file " << filename << endl;
|
||||
return 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file BaseGenerator.h
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
* (C) 2016 - 2026 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file ProxyGenerator.cpp
|
||||
*
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
|
||||
using std::endl;
|
||||
@@ -42,9 +41,6 @@ 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
|
||||
*/
|
||||
@@ -88,15 +84,15 @@ std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IProxy& proxy)" << endl
|
||||
<< tab << tab << ": m_proxy(proxy)" << endl
|
||||
<< tab << tab << ": proxy_(&proxy)" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = delete;" << endl << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
@@ -140,7 +136,7 @@ std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IProxy& m_proxy;" << endl
|
||||
<< tab << "sdbus::IProxy* proxy_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
@@ -162,7 +158,8 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
Nodes outArgs = args.select("direction" , "out");
|
||||
|
||||
bool dontExpectReply{false};
|
||||
std::optional<AsyncImpl> asyncImpl;
|
||||
bool async{false};
|
||||
bool future{false}; // Async methods implemented by means of either std::future or callbacks
|
||||
std::string timeoutValue;
|
||||
std::smatch smTimeout;
|
||||
|
||||
@@ -178,13 +175,11 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
{
|
||||
if (annotationName == "org.freedesktop.DBus.Method.Async"
|
||||
&& (annotationValue == "client" || annotationValue == "clientserver" || annotationValue == "client-server"))
|
||||
asyncImpl = AsyncImpl::Callback; // Default to callback
|
||||
async = true;
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && annotationValue == "callback")
|
||||
asyncImpl = AsyncImpl::Callback;
|
||||
future = false;
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
|
||||
asyncImpl = AsyncImpl::Future;
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
|
||||
asyncImpl = AsyncImpl::Awaitable;
|
||||
future = true;
|
||||
}
|
||||
if (annotationName == "org.freedesktop.DBus.Method.Timeout")
|
||||
timeoutValue = annotationValue;
|
||||
@@ -216,26 +211,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
std::string outArgStr, outArgTypeStr;
|
||||
std::tie(outArgStr, outArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(outArgs);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
const std::string realRetType = (async && !dontExpectReply ? (future ? "std::future<" + retType + ">" : "sdbus::PendingAsyncCall") : async ? "void" : retType);
|
||||
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
|
||||
@@ -244,13 +220,13 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
definitionSS << tab << tab << "using namespace std::chrono_literals;" << endl;
|
||||
}
|
||||
|
||||
if (outArgs.size() > 0 && !asyncImpl.has_value())
|
||||
if (outArgs.size() > 0 && !async)
|
||||
{
|
||||
definitionSS << tab << tab << retType << " result;" << endl;
|
||||
}
|
||||
|
||||
definitionSS << tab << tab << (asyncImpl.has_value() && !dontExpectReply ? "return " : "")
|
||||
<< "m_proxy.callMethod" << (asyncImpl.has_value() ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
|
||||
definitionSS << tab << tab << (async && !dontExpectReply ? "return " : "")
|
||||
<< "proxy_->callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
|
||||
|
||||
if (!timeoutValue.empty())
|
||||
{
|
||||
@@ -264,20 +240,16 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
definitionSS << ".withArguments(" << inArgStr << ")";
|
||||
}
|
||||
|
||||
if (asyncImpl.has_value() && !dontExpectReply)
|
||||
if (async && !dontExpectReply)
|
||||
{
|
||||
auto nameBigFirst = name;
|
||||
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
|
||||
|
||||
if (*asyncImpl == AsyncImpl::Future)
|
||||
if (future) // Async methods implemented through future
|
||||
{
|
||||
definitionSS << ".getResultAsFuture<" << retTypeBare << ">()";
|
||||
}
|
||||
else if (*asyncImpl == AsyncImpl::Awaitable)
|
||||
{
|
||||
definitionSS << ".getResultAsAwaitable<" << retTypeBare << ">()";
|
||||
}
|
||||
else // Callback
|
||||
else // Async methods implemented through callbacks
|
||||
{
|
||||
definitionSS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error" << (outArgTypeStr.empty() ? "" : ", ") << outArgTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "Reply(" << outArgStr << (outArgStr.empty() ? "" : ", ") << "std::move(error)); })";
|
||||
@@ -317,8 +289,8 @@ std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes&
|
||||
std::string argStr, argTypeStr;
|
||||
std::tie(argStr, argTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(args);
|
||||
|
||||
registrationSS << tab << tab << "m_proxy"
|
||||
".uponSignal(\"" << name << "\")"
|
||||
registrationSS << tab << tab << "proxy_"
|
||||
"->uponSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)"
|
||||
".call([this](" << argTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "(" << argStr << "); });" << endl;
|
||||
@@ -343,8 +315,10 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
|
||||
auto propertyArg = std::string("value");
|
||||
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
|
||||
|
||||
std::optional<AsyncImpl> asyncImplGet;
|
||||
std::optional<AsyncImpl> asyncImplSet;
|
||||
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
|
||||
|
||||
Nodes annotations = (*property)["annotation"];
|
||||
for (const auto& annotation : annotations)
|
||||
@@ -353,63 +327,37 @@ 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)
|
||||
asyncImplGet = AsyncImpl::Callback; // Default to callback
|
||||
asyncGet = true;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && annotationValue == "callback")
|
||||
asyncImplGet = AsyncImpl::Callback;
|
||||
futureGet = false;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
|
||||
asyncImplGet = AsyncImpl::Future;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Get.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
|
||||
asyncImplGet = AsyncImpl::Awaitable;
|
||||
futureGet = true;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async" && annotationValue == "client") // Server-side not supported (may be in the future)
|
||||
asyncImplSet = AsyncImpl::Callback; // Default to callback
|
||||
asyncSet = true;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && annotationValue == "callback")
|
||||
asyncImplSet = AsyncImpl::Callback;
|
||||
futureSet = false;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && (annotationValue == "future" || annotationValue == "std::future"))
|
||||
asyncImplSet = AsyncImpl::Future;
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.Set.Async.ClientImpl" && (annotationValue == "awaitable" || annotationValue == "coroutine"))
|
||||
asyncImplSet = AsyncImpl::Awaitable;
|
||||
futureSet = true;
|
||||
}
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
const std::string realRetType = (asyncGet ? (futureGet ? "std::future<sdbus::Variant>" : "sdbus::PendingAsyncCall") : propertyType);
|
||||
|
||||
propertySS << tab << realRetType << " " << propertyNameSafe << "()" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << "return m_proxy.getProperty" << (asyncImplGet.has_value() ? "Async" : "") << "(\"" << propertyName << "\")"
|
||||
propertySS << tab << tab << "return proxy_->getProperty" << (asyncGet ? "Async" : "") << "(\"" << propertyName << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
if (!asyncImplGet.has_value())
|
||||
{
|
||||
propertySS << ".get<" << realRetType << ">()";
|
||||
}
|
||||
else
|
||||
if (asyncGet)
|
||||
{
|
||||
auto nameBigFirst = propertyName;
|
||||
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
|
||||
|
||||
if (*asyncImplGet == AsyncImpl::Future)
|
||||
if (futureGet) // Async methods implemented through future
|
||||
{
|
||||
propertySS << ".getResultAsFuture()";
|
||||
}
|
||||
else if (*asyncImplGet == AsyncImpl::Awaitable)
|
||||
{
|
||||
propertySS << ".getResultAsAwaitable()";
|
||||
}
|
||||
else // Callback
|
||||
else // Async methods implemented through callbacks
|
||||
{
|
||||
propertySS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error, const sdbus::Variant& value)"
|
||||
"{ this->on" << nameBigFirst << "PropertyGetReply(value.get<" << propertyType << ">(), std::move(error)); })";
|
||||
@@ -423,46 +371,25 @@ std::tuple<std::string, std::string> ProxyGenerator::processProperties(const Nod
|
||||
|
||||
if (propertyAccess == "readwrite" || propertyAccess == "write")
|
||||
{
|
||||
if (propertySignature == "v")
|
||||
propertyArg = "{" + propertyArg + ", sdbus::embed_variant}";
|
||||
|
||||
// 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";
|
||||
}
|
||||
const std::string realRetType = (asyncSet ? (futureSet ? "std::future<void>" : "sdbus::PendingAsyncCall") : "void");
|
||||
|
||||
propertySS << tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << (asyncImplSet.has_value() ? "return " : "") << "m_proxy.setProperty" << (asyncImplSet.has_value() ? "Async" : "")
|
||||
propertySS << tab << tab << (asyncSet ? "return " : "") << "proxy_->setProperty" << (asyncSet ? "Async" : "")
|
||||
<< "(\"" << propertyName << "\")"
|
||||
".onInterface(INTERFACE_NAME)"
|
||||
".toValue(" << propertyArg << ")";
|
||||
|
||||
if (asyncImplSet.has_value())
|
||||
if (asyncSet)
|
||||
{
|
||||
auto nameBigFirst = propertyName;
|
||||
nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0];
|
||||
|
||||
if (*asyncImplSet == AsyncImpl::Future)
|
||||
if (futureSet) // Async methods implemented through future
|
||||
{
|
||||
propertySS << ".getResultAsFuture()";
|
||||
}
|
||||
else if (*asyncImplSet == AsyncImpl::Awaitable)
|
||||
{
|
||||
propertySS << ".getResultAsAwaitable()";
|
||||
}
|
||||
else // Callback
|
||||
else // Async methods implemented through callbacks
|
||||
{
|
||||
propertySS << ".uponReplyInvoke([this](std::optional<sdbus::Error> error)"
|
||||
"{ this->on" << nameBigFirst << "PropertySetReply(std::move(error)); })";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user