This implements three variants of `GetManagedObjectsAsync()` API into the standard `ObjectManager` client interface.
---------
Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
Add `Message::getCookie()` and `MethodReply::getReplyCookie()` functions, based on underlying sd-bus cookie functions. They can be useful when pairing method call messages and method call reply messages.
---------
Co-authored-by: Dylan Howey <dylan.howey@evgo.com>
Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
This allows nesting variants, i.e. allows a variant to contain another variant as its value. Until now, there was no such possibility, since the default generated copy constructor would be invoked which would create a copy of source variant instead of embed the source variant as a value in the destination variant. The default generated copy constructor is kept, for it makes sense too, but a new tag-based overload is added for embedding the source variant into the destination variant.
This extends the functionality of SDBUSCPP_REGISTER_STRUCT macro.
It now provides functionality for serializing a user-defined struct as an a{sv} dictionary, and for deserializing an a{sv} dictionary into a user-defined struct. The former one is achieved by decorating the struct with sdbus::as_dictionary(struct), the latter one is an automatic behavior -- when sdbus-c++ is asked to deserialize into a struct but the data in the message is of type a{sv}, then the dict-to-struct deserialization is performed automatically.
There are some aspects of behavior in the serialization/deserialization functionality that can be customized by the client. Newly introduced SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION and SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION macros serve the purpose.
Until now, the solution to ensure that even large messages are fully sent out has been to flush the connection queues after each sending of a message, which is likely an unnecessary call (with unnecessary cost) in vast majority of cases, and which may block the connection from doing other work until the large message is fully sent out. This was a rather quick, hacky workaround.
Now, after the sending the message we check whether it has been sent out fully or not. If not (outbound queues are non-empty), then we send a wake-up signal to the connection event loop. The event loop thread then fetches new sd-bus timeouts and events and will see that there are pending outbound messages to process, and will process them together with any other prospective pending events, until there is nothing to process (i.e., the outbound message has been fully dispatched).
This reorganizes the layers of abstraction in the sense how `Message` depends on `Connection` and vice versa. Now, `Message` has a link to the `Connection`. This replaces the shortcut link to the low-level `SdBus` interface that the `Message` kept. The interactions from `Message` now go through `Connection` which forwards them to `SdBus`. `Connection` is now a sole owner of the low-level `SdBus` interface. This allows for future changes around `SdBus` (e.g. a change from virtual functions back to non-virtual functions) without affecting the rest of the library. `Proxy`s and `Object`s can now send messages directly without having to go through `Connection`. The `Connection` no more depends on `Message` business-logic methods; it serves only as a factory for messages.
The flow for creating messages: `Proxy`/`Object` -> `Connection` -> `SdBus`
The flow for sending messages: (`Proxy`/`Object` ->) `Message` -> `Connection` -> `SdBus`
This also better reflects how dependencies are managed in the underlying sd-bus library.
Additionally, `getSdBusInterface()` methods are removed which was anyway planned, and improves the design by "Tell, don't ask" principle.
This refactoring is the necessary enabler for other upcoming improvements (regarding sending long messages, or creds refactoring, for example).
This fixes the template specialization ambiguity error when a signature_of applied upon a const (and/or volatile) enum type would render the const specialization and the enum specialization as two equally-ranked candidates.
This introduces SDBUSCPP_REGISTER_STRUCT macro that helps clients conveniently, in one line, teach sdbus-c++ to recognize and accept their custom C++ struct types wherever D-Bus structs are expected in a D-Bus API.
The macro saves some boilerplate that would otherwise be needed on client side for every registered struct.
Make all the API consistent by using return_slot_t-based overloads for returning the slots to clients, and overloads without that tag for "floating" slots. floating_slot_t tag was previously added for API backwards compatibility reasons, but now is a (counter-)duplicate to the return_slot_t.
Moving adaptor or proxy instances changes their `this` pointer. But `this` is captured by value in closures used by those instances, and this remains unchanged on move, leading to accessing an invalid instance when a lambda expression executes. Supporting move semantics would require unsubscribing/unregistering vtable, handlers, etc. and re-subscribing and re-registering all that, which is too complicated and may have side effects. Hence it has been decided that these classes are not moveable. One may use an indirection with e.g. `std::unique_ptr` to get move semantics.
Since sdbus-c++ knows types of D-Bus call/signal/property input/output parameters at compile time, why not assemble the D-Bus signature strings at compile time, too, instead of assembling them at run time as std::string with likely cost of (unnecessary) heap allocations...
std::array is well supported constexpr type in C++20, so we harness it to build the D-Bus signature string and store it into the binary at compile time.
Having explicit conversion operator is a good practice according to the C++ core guidelines, as it makes the code safer and better follows the principle of least astonishment. Also, it is consistent with the standard library style, where wrappers like std::variant, std::any, std::optional... also do not provide an implicit conversion to the underlying type. Last but not least, it paves the way for the upcoming std::variant <-> sdbus::Variant implicit conversions without surprising behavior in some edge cases.
This introduces strong types for `std::string`-based D-Bus types. This facilitates 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.
A new CMake configuration variable SDBUSCPP_SDBUS_LIB has been introduced that enables clients to specify which sd-bus implementation library shall be used by sdbus-c++.
This PR makes things around connection factories a little more consistent and more intuitive:
* createConnection() has been removed. One shall call more expressive createSystemConnection() instead to get a connection to the system bus.
* createDefaultBusConnection() has been renamed to createBusConnection(), so as not to be confused with libsystemd's default_bus, which is a different thing (a reusable thread-local bus).
Proxies still by default call createBusConnection() to get a connection when the connection is not provided explicitly by the caller, but now createBusConnection() does a different thing, so now the proxies connect to either session bus or system bus depending on the context (as opposed to always to system bus like before).
The integration tests were modified to use createBusConnection().
This improves usability of sdbus-c++ in downstream CMake projects. CMake options now have `SDBUSCPP_` prefix so potential conflicts with downstream options/variables are minimized. Also, all configurable options and variables are placed in a single place in the root CMake file.
This switches from a raw pointer to std::optional type to pass prospective call errors to the client (using std::optional was not possible years back when sdbus-c++ was based on C++14). This makes the API a little clearer, safer, idiomatically more expressive, and removes potential confusion associated with raw pointers (like ownership, lifetime questions, etc.).
This makes D-Bus proxy signal registration more flexible, more dynamic, and less error-prone since no `finishRegistration()` call is needed. A proxy can register to a signal at any time during its lifetime, and can unregister freely by simply destroying the associated slot.
This improves the D-Bus object API registration/unregistration by making it more flexible, more dynamic, closer to sd-bus API design but still on high abstraction level, and -- most importantly -- less error-prone since no `finishRegistration()` call is needed anymore.
sd_bus_match_signal() is more convenient than more general sd_bus_add_match() for signal registration, and requires less code on our side. Plus, systemd of at least v238 is required for sdbus-c++ v2, and this version already ships with sd_bus_match_signal().
This makes the library more robust and prone to user's errors when the user writes an extension for their custom type. In case they forget to implement a serialization function for that type and yet insert an object of that type into sdbus::Message, the current behavior is that, surprisingly, the library masks the error as it resolves the call to the Variant overload, because Variant provides an implicit template converting constructor, so the library tries to construct first the Variant object from the object of custom type, and then inserting into the message that Variant object. Variant constructor serializes the underlying object into its internal message object, which resolves to the same message insertion overload, creating an infinite recursion and ultimately the stack overflow. This is undesired and plain wrong. Marking this Variant converting constructor solves these problems, plus in overall it makes the code a little safer and more verbose. With explicit Variant constructor, when the user forgets to implement a serialization function for their type, the call of such function will fail with an expressive compilation error, and will produce no undesired, surprising results.
The test now works with Clang, libc++ and -O2 optimization, since the underlying implementation has been completely re-designed and doesn't suffer from that problem anymore.
Signatures of callbacks async_reply_handler, signal_handler, message_handler and property_set_callback were modified to take input message objects by value, as opposed to non-const ref.
The callee assumes ownership of the message. This API is more idiomatic, more expressive, cleaner and safer. Move semantics is used to pass messages to the callback handlers. In some cases, this also improves performance.
This also introduces `always_false` technique instead of `sizeof` trick for unsupported D-Bus type representation static assert. This one is more expressive and leads to more specific, more revealing compiler error messages.
* Change default test installation path to tests/sdbus-c++ , while also respecting CMAKE_INSTALL_PREFIX
* Introduce INSTALL_TESTS CMake option, so BUILD_TESTS is now split into BUILD_TESTS just for building and INSTALL_TESTS for installing the test binaries
Per discussion in #358 (comment), the change in the default settings is fine a for a minor release.