mirror of
https://github.com/Kistler-Group/sdbus-cpp.git
synced 2025-07-30 18:17:14 +02:00
refactor: improve and make more efficient some Message API (#432)
This commit is contained in:
@ -1780,6 +1780,8 @@ sdbus-c++ v2 is a major release that comes with a number of breaking API/ABI/beh
|
|||||||
* `createDefaultBusConnection()` has been renamed to `createBusConnection()`.
|
* `createDefaultBusConnection()` has been renamed to `createBusConnection()`.
|
||||||
* 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).
|
* 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.
|
* 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.
|
* 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.
|
||||||
* Types and methods marked deprecated in sdbus-c++ v1 were removed completely.
|
* 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 options got `SDBUSCPP_` prefix for better usability and minimal risk of conflicts in downstream CMake projects. `SDBUSCPP_INSTALL` CMake option was added.
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
@ -52,14 +53,10 @@
|
|||||||
namespace sdbus {
|
namespace sdbus {
|
||||||
class Variant;
|
class Variant;
|
||||||
class ObjectPath;
|
class ObjectPath;
|
||||||
class InterfaceName;
|
|
||||||
class MemberName;
|
|
||||||
class Signature;
|
class Signature;
|
||||||
template <typename... _ValueTypes> class Struct;
|
template <typename... _ValueTypes> class Struct;
|
||||||
class UnixFd;
|
class UnixFd;
|
||||||
class MethodReply;
|
class MethodReply;
|
||||||
class BusName;
|
|
||||||
using ConnectionName = BusName;
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
class ISdBus;
|
class ISdBus;
|
||||||
}
|
}
|
||||||
@ -202,12 +199,13 @@ namespace sdbus {
|
|||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
void clearFlags();
|
void clearFlags();
|
||||||
|
|
||||||
InterfaceName getInterfaceName() const;
|
const char* getInterfaceName() const;
|
||||||
MemberName getMemberName() const;
|
const char* getMemberName() const;
|
||||||
ConnectionName getSender() const;
|
const char* getSender() const;
|
||||||
ObjectPath getPath() const;
|
const char* getPath() const;
|
||||||
ConnectionName getDestination() const;
|
const char* getDestination() const;
|
||||||
void peekType(std::string& type, std::string& contents) const;
|
// TODO: short docs in whole Message API
|
||||||
|
std::pair<char, const char*> peekType() const;
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
bool isAtEnd(bool complete) const;
|
bool isAtEnd(bool complete) const;
|
||||||
@ -302,7 +300,8 @@ namespace sdbus {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Signal() = default;
|
Signal() = default;
|
||||||
void setDestination(const ConnectionName& destination);
|
void setDestination(const std::string& destination);
|
||||||
|
void setDestination(const char* destination);
|
||||||
void send() const;
|
void send() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -474,15 +473,14 @@ namespace sdbus {
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template <typename _Element, typename... _Elements>
|
template <typename _Element, typename... _Elements>
|
||||||
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const std::string& signature)
|
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const char* signature)
|
||||||
{
|
{
|
||||||
constexpr auto elemSignature = sdbus::signature_of_v<_Element>;
|
constexpr auto elemSignature = as_null_terminated(sdbus::signature_of_v<_Element>);
|
||||||
// TODO: Try to optimize
|
if (std::strcmp(signature, elemSignature.data()) != 0)
|
||||||
if (signature != std::string(elemSignature.begin(), elemSignature.end()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_Element temp;
|
_Element temp;
|
||||||
msg.enterVariant(signature.c_str());
|
msg.enterVariant(signature);
|
||||||
msg >> temp;
|
msg >> temp;
|
||||||
msg.exitVariant();
|
msg.exitVariant();
|
||||||
value = std::move(temp);
|
value = std::move(temp);
|
||||||
@ -493,11 +491,8 @@ namespace sdbus {
|
|||||||
template <typename... Elements>
|
template <typename... Elements>
|
||||||
inline Message& Message::operator>>(std::variant<Elements...>& value)
|
inline Message& Message::operator>>(std::variant<Elements...>& value)
|
||||||
{
|
{
|
||||||
std::string type;
|
auto [type, contents] = peekType();
|
||||||
std::string contentType;
|
bool result = (detail::deserialize_variant<Elements>(*this, value, contents) || ...);
|
||||||
// TODO: Refactor ppekType prior to release/v2.0 to return pair of const char* or string_view...
|
|
||||||
peekType(type, contentType);
|
|
||||||
bool result = (detail::deserialize_variant<Elements>(*this, value, contentType) || ...);
|
|
||||||
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
|
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <sdbus-c++/Message.h>
|
#include <sdbus-c++/Message.h>
|
||||||
#include <sdbus-c++/TypeTraits.h>
|
#include <sdbus-c++/TypeTraits.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@ -105,14 +106,14 @@ namespace sdbus {
|
|||||||
bool containsValueOfType() const
|
bool containsValueOfType() const
|
||||||
{
|
{
|
||||||
constexpr auto signature = as_null_terminated(signature_of_v<_Type>);
|
constexpr auto signature = as_null_terminated(signature_of_v<_Type>);
|
||||||
return signature.data() == peekValueType();
|
return std::strcmp(signature.data(), peekValueType()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
|
|
||||||
void serializeTo(Message& msg) const;
|
void serializeTo(Message& msg) const;
|
||||||
void deserializeFrom(Message& msg);
|
void deserializeFrom(Message& msg);
|
||||||
std::string peekValueType() const;
|
const char* peekValueType() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable PlainMessage msg_{};
|
mutable PlainMessage msg_{};
|
||||||
|
@ -612,44 +612,38 @@ void Message::rewind(bool complete)
|
|||||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
|
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
|
||||||
}
|
}
|
||||||
|
|
||||||
InterfaceName Message::getInterfaceName() const
|
const char* Message::getInterfaceName() const
|
||||||
{
|
{
|
||||||
const auto* interface = sd_bus_message_get_interface((sd_bus_message*)msg_);
|
return sd_bus_message_get_interface((sd_bus_message*)msg_);
|
||||||
return interface != nullptr ? InterfaceName{interface} : InterfaceName{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberName Message::getMemberName() const
|
const char* Message::getMemberName() const
|
||||||
{
|
{
|
||||||
const auto* member = sd_bus_message_get_member((sd_bus_message*)msg_);
|
return sd_bus_message_get_member((sd_bus_message*)msg_);
|
||||||
return member != nullptr ? MemberName{member} : MemberName{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionName Message::getSender() const
|
const char* Message::getSender() const
|
||||||
{
|
{
|
||||||
const auto* sender = sd_bus_message_get_sender((sd_bus_message*)msg_);
|
return sd_bus_message_get_sender((sd_bus_message*)msg_);
|
||||||
return ConnectionName{sender};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPath Message::getPath() const
|
const char* Message::getPath() const
|
||||||
{
|
{
|
||||||
const auto* path = sd_bus_message_get_path((sd_bus_message*)msg_);
|
return sd_bus_message_get_path((sd_bus_message*)msg_);
|
||||||
return path != nullptr ? ObjectPath{path} : ObjectPath{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionName Message::getDestination() const
|
const char* Message::getDestination() const
|
||||||
{
|
{
|
||||||
const auto* destination = sd_bus_message_get_destination((sd_bus_message*)msg_);
|
return sd_bus_message_get_destination((sd_bus_message*)msg_);
|
||||||
return destination != nullptr ? ConnectionName{destination} : ConnectionName{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Message::peekType(std::string& type, std::string& contents) const
|
std::pair<char, const char*> Message::peekType() const
|
||||||
{
|
{
|
||||||
char typeSig;
|
char typeSignature{};
|
||||||
const char* contentsSig;
|
const char* contentsSignature{};
|
||||||
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSig, &contentsSig);
|
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSignature, &contentsSignature);
|
||||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
|
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
|
||||||
type = typeSig;
|
return {typeSignature, contentsSignature};
|
||||||
contents = contentsSig ? contentsSig : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Message::isValid() const
|
bool Message::isValid() const
|
||||||
@ -877,9 +871,14 @@ void Signal::send() const
|
|||||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
|
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Signal::setDestination(const ConnectionName& destination)
|
void Signal::setDestination(const std::string& destination)
|
||||||
{
|
{
|
||||||
auto r = sdbus_->sd_bus_message_set_destination((sd_bus_message*)msg_, destination.c_str());
|
return setDestination(destination.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal::setDestination(const char* destination)
|
||||||
|
{
|
||||||
|
auto r = sdbus_->sd_bus_message_set_destination((sd_bus_message*)msg_, destination);
|
||||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
|
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,8 +300,6 @@ const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, std::
|
|||||||
return methodItem.name < methodName;
|
return methodItem.name < methodName;
|
||||||
});
|
});
|
||||||
|
|
||||||
(void)it;
|
|
||||||
|
|
||||||
return it != vtable.methods.end() && it->name == methodName ? &*it : nullptr;
|
return it != vtable.methods.end() && it->name == methodName ? &*it : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,8 +310,6 @@ const Object::VTable::PropertyItem* Object::findProperty(const VTable& vtable, s
|
|||||||
return propertyItem.name < propertyName;
|
return propertyItem.name < propertyName;
|
||||||
});
|
});
|
||||||
|
|
||||||
(void)it;
|
|
||||||
|
|
||||||
return it != vtable.properties.end() && it->name == propertyName ? &*it : nullptr;
|
return it != vtable.properties.end() && it->name == propertyName ? &*it : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +329,7 @@ int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData,
|
|||||||
|
|
||||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_.getSdBusInterface());
|
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_.getSdBusInterface());
|
||||||
|
|
||||||
const auto* methodItem = findMethod(*vtable, message.getMemberName()); // TODO: optimize the situation around getMemberName()
|
const auto* methodItem = findMethod(*vtable, message.getMemberName());
|
||||||
assert(methodItem != nullptr);
|
assert(methodItem != nullptr);
|
||||||
assert(methodItem->callback);
|
assert(methodItem->callback);
|
||||||
|
|
||||||
|
@ -113,7 +113,6 @@ PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_h
|
|||||||
|
|
||||||
pendingAsyncCalls_.addCall(std::move(callData));
|
pendingAsyncCalls_.addCall(std::move(callData));
|
||||||
|
|
||||||
// TODO: Instead of PendingAsyncCall consider using Slot implementation for simplicity and consistency
|
|
||||||
return {weakData};
|
return {weakData};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,12 +55,10 @@ void Variant::deserializeFrom(Message& msg)
|
|||||||
msg_.seal();
|
msg_.seal();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Variant::peekValueType() const
|
const char* Variant::peekValueType() const
|
||||||
{
|
{
|
||||||
msg_.rewind(false);
|
msg_.rewind(false);
|
||||||
std::string type;
|
auto [type, contents] = msg_.peekType();
|
||||||
std::string contents;
|
|
||||||
msg_.peekType(type, contents);
|
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ using ::testing::ElementsAre;
|
|||||||
using ::testing::Eq;
|
using ::testing::Eq;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using namespace sdbus::test;
|
using namespace sdbus::test;
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
using ADirectConnection = TestFixtureWithDirectConnection;
|
using ADirectConnection = TestFixtureWithDirectConnection;
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ TYPED_TEST(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule)
|
|||||||
std::atomic<size_t> numberOfMatchingMessages{};
|
std::atomic<size_t> numberOfMatchingMessages{};
|
||||||
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
|
auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message msg)
|
||||||
{
|
{
|
||||||
if(msg.getMemberName() == "simpleSignal")
|
if(msg.getMemberName() == "simpleSignal"sv)
|
||||||
numberOfMatchingMessages++;
|
numberOfMatchingMessages++;
|
||||||
});
|
});
|
||||||
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
|
||||||
|
@ -32,8 +32,10 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
using ::testing::Eq;
|
using ::testing::Eq;
|
||||||
|
using ::testing::StrEq;
|
||||||
using ::testing::Gt;
|
using ::testing::Gt;
|
||||||
using ::testing::DoubleEq;
|
using ::testing::DoubleEq;
|
||||||
|
using ::testing::IsNull;
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -465,11 +467,10 @@ TEST(AMessage, CanPeekASimpleType)
|
|||||||
msg << 123;
|
msg << 123;
|
||||||
msg.seal();
|
msg.seal();
|
||||||
|
|
||||||
std::string type;
|
auto [type, contents] = msg.peekType();
|
||||||
std::string contents;
|
|
||||||
msg.peekType(type, contents);
|
ASSERT_THAT(type, Eq('i'));
|
||||||
ASSERT_THAT(type, "i");
|
ASSERT_THAT(contents, IsNull());
|
||||||
ASSERT_THAT(contents, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(AMessage, CanPeekContainerContents)
|
TEST(AMessage, CanPeekContainerContents)
|
||||||
@ -478,11 +479,10 @@ TEST(AMessage, CanPeekContainerContents)
|
|||||||
msg << std::map<int, std::string>{{1, "one"}, {2, "two"}};
|
msg << std::map<int, std::string>{{1, "one"}, {2, "two"}};
|
||||||
msg.seal();
|
msg.seal();
|
||||||
|
|
||||||
std::string type;
|
auto [type, contents] = msg.peekType();
|
||||||
std::string contents;
|
|
||||||
msg.peekType(type, contents);
|
ASSERT_THAT(type, Eq('a'));
|
||||||
ASSERT_THAT(type, "a");
|
ASSERT_THAT(contents, StrEq("{is}"));
|
||||||
ASSERT_THAT(contents, "{is}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(AMessage, CanCarryDBusArrayGivenAsCustomType)
|
TEST(AMessage, CanCarryDBusArrayGivenAsCustomType)
|
||||||
|
Reference in New Issue
Block a user