Skip to content

Commit 59655fe

Browse files
omartijnmartijn-resolumesangelovic
authored
refactor: use move-only callables (#531)
This enables callbacks to use move-only captures, and to move captures out. --------- Co-authored-by: Martijn Otto <martijn@resolume.com> Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
1 parent aa8a13b commit 59655fe

16 files changed

Lines changed: 190 additions & 166 deletions

.clang-format

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# TODO: Introduce common clang-format rule set
2+
DisableFormat: true
3+
SortIncludes: false

include/sdbus-c++/ConvenienceApiClasses.inl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ namespace sdbus {
304304
template <typename Function>
305305
inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(Function&& callback)
306306
{
307-
return [callback = std::forward<Function>(callback)](MethodReply reply, std::optional<Error> error)
307+
return [callback = std::forward<Function>(callback)](MethodReply reply, std::optional<Error> error) mutable
308308
{
309309
// Create a tuple of callback input arguments' types, which will be used
310310
// as a storage for the argument values deserialized from the message.
@@ -334,18 +334,18 @@ namespace sdbus {
334334
template <typename... Args>
335335
std::future<future_return_t<Args...>> AsyncMethodInvoker::getResultAsFuture()
336336
{
337-
auto promise = std::make_shared<std::promise<future_return_t<Args...>>>();
338-
auto future = promise->get_future();
337+
std::promise<future_return_t<Args...>> promise{};
338+
auto future = promise.get_future();
339339

340-
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, Args... args)
340+
uponReplyInvoke([promise = std::move(promise)](std::optional<Error> error, Args... args) mutable
341341
{
342342
if (!error)
343343
if constexpr (!std::is_void_v<future_return_t<Args...>>)
344-
promise->set_value({std::move(args)...});
344+
promise.set_value({std::move(args)...});
345345
else
346-
promise->set_value();
346+
promise.set_value();
347347
else
348-
promise->set_exception(std::make_exception_ptr(*std::move(error)));
348+
promise.set_exception(std::make_exception_ptr(*std::move(error)));
349349
});
350350

351351
// Will be std::future<void> for no D-Bus method return value
@@ -436,7 +436,7 @@ namespace sdbus {
436436
template <typename Function>
437437
inline signal_handler SignalSubscriber::makeSignalHandler(Function&& callback)
438438
{
439-
return [callback = std::forward<Function>(callback)](Signal signal)
439+
return [callback = std::forward<Function>(callback)](Signal signal) mutable
440440
{
441441
// Create a tuple of callback input arguments' types, which will be used
442442
// as a storage for the argument values deserialized from the signal message.

include/sdbus-c++/IConnection.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ namespace sdbus {
277277
*
278278
* @throws sdbus::Error in case of failure
279279
*/
280-
virtual void addMatch(const std::string& match, message_handler callback) = 0;
280+
virtual void addMatch(const std::string& match, message_handler&& callback) = 0;
281281

282282
/*!
283283
* @brief Installs a match rule for messages received on this bus connection
@@ -300,14 +300,14 @@ namespace sdbus {
300300
*
301301
* @throws sdbus::Error in case of failure
302302
*/
303-
[[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler callback, return_slot_t) = 0;
303+
[[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler&& callback, return_slot_t) = 0;
304304

305305
/*!
306306
* @brief Asynchronously installs a floating match rule for messages received on this bus connection
307307
*
308308
* @param[in] match Match expression to filter incoming D-Bus message
309309
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
310-
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
310+
* @param[in] installCallback One-shot handler invoked once with the broker's response to the install request
311311
*
312312
* This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously,
313313
* in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response.
@@ -323,14 +323,14 @@ namespace sdbus {
323323
*
324324
* @throws sdbus::Error in case of failure
325325
*/
326-
virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0;
326+
virtual void addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) = 0;
327327

328328
/*!
329329
* @brief Asynchronously installs a match rule for messages received on this bus connection
330330
*
331331
* @param[in] match Match expression to filter incoming D-Bus message
332332
* @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule
333-
* @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule
333+
* @param[in] installCallback One-shot handler invoked once with the broker's response to the install request
334334
* @return RAII-style slot handle representing the ownership of the subscription
335335
*
336336
* This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously,
@@ -347,8 +347,8 @@ namespace sdbus {
347347
* @throws sdbus::Error in case of failure
348348
*/
349349
[[nodiscard]] virtual Slot addMatchAsync( const std::string& match
350-
, message_handler callback
351-
, message_handler installCallback
350+
, message_handler&& callback
351+
, match_install_handler&& installCallback
352352
, return_slot_t ) = 0;
353353

354354
/*!

include/sdbus-c++/IObject.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,13 +442,23 @@ namespace sdbus {
442442
template <typename... VTableItems, typename>
443443
void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items)
444444
{
445-
addVTable(std::move(interfaceName), {std::forward<VTableItems>(items)...});
445+
// Built via emplace_back rather than a braced initializer_list: items hold move-only
446+
// callbacks, and initializer_list elements are const (copy-only).
447+
std::vector<VTableItem> vtable;
448+
vtable.reserve(sizeof...(items));
449+
(vtable.emplace_back(std::forward<VTableItems>(items)), ...);
450+
addVTable(std::move(interfaceName), std::move(vtable));
446451
}
447452

448453
template <typename... VTableItems, typename>
449454
VTableAdder IObject::addVTable(VTableItems&&... items)
450455
{
451-
return addVTable(std::vector<VTableItem>{std::forward<VTableItems>(items)...});
456+
// Built via emplace_back rather than a braced initializer_list: items hold move-only
457+
// callbacks, and initializer_list elements are const (copy-only).
458+
std::vector<VTableItem> vtable;
459+
vtable.reserve(sizeof...(items));
460+
(vtable.emplace_back(std::forward<VTableItems>(items)), ...);
461+
return addVTable(std::move(vtable));
452462
}
453463

454464
inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)

include/sdbus-c++/IProxy.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ namespace sdbus {
455455
*
456456
* @throws sdbus::Error in case of failure
457457
*/
458-
virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) = 0;
458+
virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) = 0;
459459

460460
/*!
461461
* @brief Calls method on the D-Bus object asynchronously
@@ -480,7 +480,7 @@ namespace sdbus {
480480
* @throws sdbus::Error in case of failure
481481
*/
482482
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
483-
, async_reply_handler asyncReplyCallback
483+
, async_reply_handler&& asyncReplyCallback
484484
, return_slot_t ) = 0;
485485

486486
/*!
@@ -506,7 +506,7 @@ namespace sdbus {
506506
* @throws sdbus::Error in case of failure
507507
*/
508508
virtual PendingAsyncCall callMethodAsync( const MethodCall& message
509-
, async_reply_handler asyncReplyCallback
509+
, async_reply_handler&& asyncReplyCallback
510510
, uint64_t timeout ) = 0;
511511

512512
/*!
@@ -533,7 +533,7 @@ namespace sdbus {
533533
* @throws sdbus::Error in case of failure
534534
*/
535535
[[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message
536-
, async_reply_handler asyncReplyCallback
536+
, async_reply_handler&& asyncReplyCallback
537537
, uint64_t timeout
538538
, return_slot_t ) = 0;
539539

@@ -542,15 +542,15 @@ namespace sdbus {
542542
*/
543543
template <typename Rep, typename Period>
544544
PendingAsyncCall callMethodAsync( const MethodCall& message
545-
, async_reply_handler asyncReplyCallback
545+
, async_reply_handler&& asyncReplyCallback
546546
, const std::chrono::duration<Rep, Period>& timeout );
547547

548548
/*!
549549
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t,return_slot_t)
550550
*/
551551
template <typename Rep, typename Period>
552552
[[nodiscard]] Slot callMethodAsync( const MethodCall& message
553-
, async_reply_handler asyncReplyCallback
553+
, async_reply_handler&& asyncReplyCallback
554554
, const std::chrono::duration<Rep, Period>& timeout
555555
, return_slot_t );
556556

@@ -669,7 +669,7 @@ namespace sdbus {
669669
*/
670670
virtual void registerSignalHandler( const InterfaceName& interfaceName
671671
, const SignalName& signalName
672-
, signal_handler signalHandler ) = 0;
672+
, signal_handler&& signalHandler ) = 0;
673673

674674
/*!
675675
* @brief Registers a handler for the desired signal emitted by the D-Bus object
@@ -689,7 +689,7 @@ namespace sdbus {
689689
*/
690690
[[nodiscard]] virtual Slot registerSignalHandler( const InterfaceName& interfaceName
691691
, const SignalName& signalName
692-
, signal_handler signalHandler
692+
, signal_handler&& signalHandler
693693
, return_slot_t ) = 0;
694694

695695
protected: // Internal API for efficiency reasons used by high-level API helper classes
@@ -700,10 +700,10 @@ namespace sdbus {
700700
[[nodiscard]] virtual MethodCall createMethodCall(const char* interfaceName, const char* methodName) const = 0;
701701
virtual void registerSignalHandler( const char* interfaceName
702702
, const char* signalName
703-
, signal_handler signalHandler ) = 0;
703+
, signal_handler&& signalHandler ) = 0;
704704
[[nodiscard]] virtual Slot registerSignalHandler( const char* interfaceName
705705
, const char* signalName
706-
, signal_handler signalHandler
706+
, signal_handler&& signalHandler
707707
, return_slot_t ) = 0;
708708
};
709709

@@ -759,7 +759,7 @@ namespace sdbus {
759759

760760
template <typename Rep, typename Period>
761761
inline PendingAsyncCall IProxy::callMethodAsync( const MethodCall& message
762-
, async_reply_handler asyncReplyCallback
762+
, async_reply_handler&& asyncReplyCallback
763763
, const std::chrono::duration<Rep, Period>& timeout )
764764
{
765765
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
@@ -768,7 +768,7 @@ namespace sdbus {
768768

769769
template <typename Rep, typename Period>
770770
inline Slot IProxy::callMethodAsync( const MethodCall& message
771-
, async_reply_handler asyncReplyCallback
771+
, async_reply_handler&& asyncReplyCallback
772772
, const std::chrono::duration<Rep, Period>& timeout
773773
, return_slot_t )
774774
{

include/sdbus-c++/TypeTraits.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,21 @@ namespace sdbus {
7474
namespace sdbus {
7575

7676
// Callbacks from sdbus-c++
77-
using method_callback = std::function<void(MethodCall msg)>;
78-
using async_reply_handler = std::function<void(MethodReply reply, std::optional<Error> error)>;
79-
using signal_handler = std::function<void(Signal signal)>;
80-
using message_handler = std::function<void(Message msg)>;
81-
using property_set_callback = std::function<void(PropertySetCall msg)>;
82-
using property_get_callback = std::function<void(PropertyGetReply& reply)>;
77+
// Repeatable server-side and client-side callbacks
78+
using method_callback = std::move_only_function<void(MethodCall msg)>;
79+
using property_set_callback = std::move_only_function<void(PropertySetCall msg)>;
80+
using property_get_callback = std::move_only_function<void(PropertyGetReply& reply)>;
81+
using signal_handler = std::move_only_function<void(Signal signal)>;
82+
using message_handler = std::move_only_function<void(Message msg)>;
83+
84+
// One-shot callbacks: invoked exactly once (async reply arrives / match rule installed).
85+
// Rvalue-qualified so the library must std::move to invoke, making the call-once contract
86+
// visible at the call site and letting handlers move-consume captured resources.
87+
using async_reply_handler = std::move_only_function<void(MethodReply reply, std::optional<Error> error) &&>;
88+
using match_install_handler = std::move_only_function<void(Message msg) &&>;
8389

8490
// Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++
85-
using Slot = std::unique_ptr<void, std::function<void(void*)>>;
91+
using Slot = std::unique_ptr<void, std::move_only_function<void(void*)>>;
8692

8793
// Tag specifying that an owning handle (so-called slot) of the logical resource shall be provided to the client
8894
struct return_slot_t { explicit return_slot_t() = default; };
@@ -380,6 +386,9 @@ namespace sdbus {
380386
static constexpr bool is_trivial_dbus_type = false;
381387
};
382388

389+
template <typename... Types>
390+
concept valid_signature = signature_of<Types...>::is_valid;
391+
383392
// To simplify conversions of arrays to C strings
384393
template <typename T, std::size_t N>
385394
constexpr auto as_null_terminated(std::array<T, N> arr)
@@ -508,6 +517,10 @@ namespace sdbus {
508517
struct function_traits<std::function<FunctionType>> : function_traits<FunctionType>
509518
{};
510519

520+
template <typename FunctionType>
521+
struct function_traits<std::move_only_function<FunctionType>> : function_traits<FunctionType>
522+
{};
523+
511524
template <class Function>
512525
constexpr auto is_async_method_v = function_traits<Function>::is_async;
513526

include/sdbus-c++/VTableItems.h

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ namespace sdbus {
3838

3939
struct MethodVTableItem
4040
{
41-
template <typename Function> MethodVTableItem& implementedAs(Function&& callback);
42-
MethodVTableItem& withInputParamNames(std::vector<std::string> names);
43-
template <typename... String> MethodVTableItem& withInputParamNames(String... names);
44-
MethodVTableItem& withOutputParamNames(std::vector<std::string> names);
45-
template <typename... String> MethodVTableItem& withOutputParamNames(String... names);
46-
MethodVTableItem& markAsDeprecated();
47-
MethodVTableItem& markAsPrivileged();
48-
MethodVTableItem& withNoReply();
41+
template <typename Function> MethodVTableItem&& implementedAs(Function&& callback) &&;
42+
MethodVTableItem&& withInputParamNames(std::vector<std::string> names) &&;
43+
template <typename... String> MethodVTableItem&& withInputParamNames(String... names) &&;
44+
MethodVTableItem&& withOutputParamNames(std::vector<std::string> names) &&;
45+
template <typename... String> MethodVTableItem&& withOutputParamNames(String... names) &&;
46+
MethodVTableItem&& markAsDeprecated() &&;
47+
MethodVTableItem&& markAsPrivileged() &&;
48+
MethodVTableItem&& withNoReply() &&;
4949

5050
MethodName name;
5151
Signature inputSignature;
@@ -61,10 +61,10 @@ namespace sdbus {
6161

6262
struct SignalVTableItem
6363
{
64-
template <typename... Args> SignalVTableItem& withParameters();
65-
template <typename... Args> SignalVTableItem& withParameters(std::vector<std::string> names);
66-
template <typename... Args, typename... String> SignalVTableItem& withParameters(String... names);
67-
SignalVTableItem& markAsDeprecated();
64+
template <typename... Args> SignalVTableItem&& withParameters() &&;
65+
template <typename... Args> SignalVTableItem&& withParameters(std::vector<std::string> names) &&;
66+
template <typename... Args, typename... String> SignalVTableItem&& withParameters(String... names) &&;
67+
SignalVTableItem&& markAsDeprecated() &&;
6868

6969
SignalName name;
7070
Signature signature;
@@ -77,11 +77,11 @@ namespace sdbus {
7777

7878
struct PropertyVTableItem
7979
{
80-
template <typename Function> PropertyVTableItem& withGetter(Function&& callback);
81-
template <typename Function> PropertyVTableItem& withSetter(Function&& callback);
82-
PropertyVTableItem& markAsDeprecated();
83-
PropertyVTableItem& markAsPrivileged();
84-
PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
80+
template <typename Function> PropertyVTableItem&& withGetter(Function&& callback) &&;
81+
template <typename Function> PropertyVTableItem&& withSetter(Function&& callback) &&;
82+
PropertyVTableItem&& markAsDeprecated() &&;
83+
PropertyVTableItem&& markAsPrivileged() &&;
84+
PropertyVTableItem&& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&;
8585

8686
PropertyName name;
8787
Signature signature;
@@ -95,10 +95,10 @@ namespace sdbus {
9595

9696
struct InterfaceFlagsVTableItem
9797
{
98-
InterfaceFlagsVTableItem& markAsDeprecated();
99-
InterfaceFlagsVTableItem& markAsPrivileged();
100-
InterfaceFlagsVTableItem& withNoReplyMethods();
101-
InterfaceFlagsVTableItem& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
98+
InterfaceFlagsVTableItem&& markAsDeprecated() &&;
99+
InterfaceFlagsVTableItem&& markAsPrivileged() &&;
100+
InterfaceFlagsVTableItem&& withNoReplyMethods() &&;
101+
InterfaceFlagsVTableItem&& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&;
102102

103103
Flags flags;
104104
};

0 commit comments

Comments
 (0)