From c422de641a703cd33de73b4c534cba7cb7577ada Mon Sep 17 00:00:00 2001 From: Stanislav Angelovic Date: Thu, 22 Jul 2021 15:48:50 +0200 Subject: [PATCH] Support Error parameter in signal handlers --- docs/using-sdbus-c++.md | 9 ++++++ include/sdbus-c++/ConvenienceApiClasses.inl | 31 ++++++++++++++++++--- include/sdbus-c++/TypeTraits.h | 5 ++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/docs/using-sdbus-c++.md b/docs/using-sdbus-c++.md index e9a3860..a4c703b 100644 --- a/docs/using-sdbus-c++.md +++ b/docs/using-sdbus-c++.md @@ -546,6 +546,15 @@ When registering methods, calling methods or emitting signals, multiple lines of sdbus-c++ users shall prefer the convenience API to the lower level, basic API. When feasible, using generated adaptor and proxy stubs is even better. These stubs provide yet another, higher API level built on top of the convenience API. They are described in the following section. +> **_Note_:** By default, signal callback handlers are not invoked (i.e., the signal is silently dropped) if there is a signal signature mismatch. If clients want to be informed of such situations, they can prepend `const sdbus::Error*` parameter to their signal callback handler's parameter list. This argument will be `nullptr` in normal cases, and will provide access to the corresponding `sdbus::Error` object in case of deserialization failures. An example of a handler with the signature (`int`) different from the real signal contents (`string`): +> ```c++ +> void onConcatenated(const sdbus::Error* e, int wrongParameter) +> { +> assert(e); +> assert(e->getMessage() == "Failed to deserialize a int32 value"); +> } +> ``` + > **_Tip_:** When registering a D-Bus object, we can additionally provide names of input and output parameters of its methods and names of parameters of its signals. When the object is introspected, these names are listed in the resulting introspection XML, which improves the description of object's interfaces: > ```c++ > concatenator->registerMethod("concatenate") diff --git a/include/sdbus-c++/ConvenienceApiClasses.inl b/include/sdbus-c++/ConvenienceApiClasses.inl index d144818..200557e 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.inl +++ b/include/sdbus-c++/ConvenienceApiClasses.inl @@ -640,11 +640,34 @@ namespace sdbus { // as a storage for the argument values deserialized from the signal message. tuple_of_function_input_arg_types_t<_Function> signalArgs; - // Deserialize input arguments from the signal message into the tuple - signal >> signalArgs; + // The signal handler can take pure signal parameters only, or an additional `const 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 as a non-zero Error pointer to the client's signal handler. + if constexpr (has_error_param_v<_Function>) + { + // Deserialize input arguments from the signal message into the tuple + try + { + signal >> signalArgs; + } + catch (const sdbus::Error& e) + { + // Invoke callback with error argument and input arguments from the tuple. + sdbus::apply(callback, &e, signalArgs); + } - // Invoke callback with input arguments from the tuple. - sdbus::apply(callback, signalArgs); + // Invoke callback with no error and input arguments from the tuple. + sdbus::apply(callback, nullptr, signalArgs); + } + else + { + // Deserialize input arguments from the signal message into the tuple + signal >> signalArgs; + + // Invoke callback with input arguments from the tuple. + sdbus::apply(callback, signalArgs); + } }); } diff --git a/include/sdbus-c++/TypeTraits.h b/include/sdbus-c++/TypeTraits.h index 4680829..2f8560c 100644 --- a/include/sdbus-c++/TypeTraits.h +++ b/include/sdbus-c++/TypeTraits.h @@ -378,12 +378,14 @@ namespace sdbus { : public function_traits_base<_ReturnType, _Args...> { static constexpr bool is_async = false; + static constexpr bool has_error_param = false; }; template struct function_traits : public function_traits_base { + static constexpr bool has_error_param = true; }; template @@ -443,6 +445,9 @@ namespace sdbus { template constexpr auto is_async_method_v = function_traits<_Function>::is_async; + template + constexpr auto has_error_param_v = function_traits<_Function>::has_error_param; + template using function_arguments_t = typename function_traits<_FunctionType>::arguments_type;