Add support for appending std::string_view
std::string_view is used more in the project now that c++17 is
available. It should be allowed as a base type in serialization of dbus
interfaces.
To avoid an extra string copy, this function makes use of
sd_bus_message_append_string_iovec, which allows appending in string
pieces that might not be null terminated. This function is piped
through the test framework, and interfaces to match.
Change-Id: Iee3e2cea9759fa9759cec98ab30c12c822aa3b73
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/include/sdbusplus/message/append.hpp b/include/sdbusplus/message/append.hpp
index d198994..ddd71ce 100644
--- a/include/sdbusplus/message/append.hpp
+++ b/include/sdbusplus/message/append.hpp
@@ -8,6 +8,8 @@
#include <sdbusplus/utility/tuple_to_array.hpp>
#include <sdbusplus/utility/type_traits.hpp>
+#include <bit>
+#include <string_view>
#include <tuple>
#include <type_traits>
#include <variant>
@@ -213,6 +215,18 @@
}
};
+/** @brief Specialization of append_single for std::string_views. */
+template <>
+struct append_single<std::string_view>
+{
+ template <typename T>
+ static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
+ {
+ iovec iov{std::bit_cast<void*>(s.data()), s.size()};
+ intf->sd_bus_message_append_string_iovec(m, &iov, 1);
+ }
+};
+
/** @brief Specialization of append_single for details::string_wrapper. */
template <>
struct append_single<details::string_wrapper>
diff --git a/include/sdbusplus/message/types.hpp b/include/sdbusplus/message/types.hpp
index faaf23a..e4be6a5 100644
--- a/include/sdbusplus/message/types.hpp
+++ b/include/sdbusplus/message/types.hpp
@@ -220,6 +220,9 @@
struct type_id<std::string> : tuple_type_id<SD_BUS_TYPE_STRING>
{};
template <>
+struct type_id<std::string_view> : tuple_type_id<SD_BUS_TYPE_STRING>
+{};
+template <>
struct type_id<object_path> : tuple_type_id<SD_BUS_TYPE_OBJECT_PATH>
{};
template <>
diff --git a/include/sdbusplus/sdbus.hpp b/include/sdbusplus/sdbus.hpp
index 37b7635..7f0a569 100644
--- a/include/sdbusplus/sdbus.hpp
+++ b/include/sdbusplus/sdbus.hpp
@@ -73,6 +73,10 @@
virtual int sd_bus_message_append_basic(sd_bus_message* message, char type,
const void* value) = 0;
+ virtual int sd_bus_message_append_string_iovec(sd_bus_message* message,
+ const struct iovec* iov,
+ int iovcnt) = 0;
+
virtual int sd_bus_message_at_end(sd_bus_message* m, int complete) = 0;
virtual int sd_bus_message_close_container(sd_bus_message* m) = 0;
@@ -315,6 +319,13 @@
return ::sd_bus_message_append_basic(message, type, value);
}
+ int sd_bus_message_append_string_iovec(sd_bus_message* message,
+ const struct iovec* iov,
+ int iovcnt) override
+ {
+ return ::sd_bus_message_append_string_iovec(message, iov, iovcnt);
+ }
+
int sd_bus_message_at_end(sd_bus_message* m, int complete) override
{
return ::sd_bus_message_at_end(m, complete);
diff --git a/include/sdbusplus/test/sdbus_mock.hpp b/include/sdbusplus/test/sdbus_mock.hpp
index c61fe1c..01dc819 100644
--- a/include/sdbusplus/test/sdbus_mock.hpp
+++ b/include/sdbusplus/test/sdbus_mock.hpp
@@ -62,6 +62,9 @@
MOCK_METHOD(int, sd_bus_message_append_basic,
(sd_bus_message*, char, const void*), (override));
+ MOCK_METHOD(int, sd_bus_message_append_string_iovec,
+ (sd_bus_message*, const struct iovec* iov, int iovcnt),
+ (override));
MOCK_METHOD(int, sd_bus_message_at_end, (sd_bus_message*, int), (override));
MOCK_METHOD(int, sd_bus_message_close_container, (sd_bus_message*),
(override));
diff --git a/test/message/append.cpp b/test/message/append.cpp
index 59e83b4..b0ef54e 100644
--- a/test/message/append.cpp
+++ b/test/message/append.cpp
@@ -27,6 +27,12 @@
using testing::SafeMatcherCast;
using testing::StrEq;
+MATCHER_P(iovec_equal, match_string, "")
+{
+ const char* start = std::bit_cast<char*>(arg->iov_base);
+ return std::string(start, arg->iov_len) == match_string;
+}
+
class AppendTest : public testing::Test
{
protected:
@@ -64,6 +70,13 @@
SafeMatcherCast<const char*>(StrEq(str)))))
.WillOnce(Return(0));
}
+ void expect_basic_string_iovec(const char* str, size_t size)
+ {
+ std::string tmp = {str, size};
+ EXPECT_CALL(mock, sd_bus_message_append_string_iovec(
+ nullptr, iovec_equal(tmp), 1))
+ .WillOnce(Return(0));
+ }
void expect_open_container(char type, const char* contents)
{
@@ -187,6 +200,20 @@
new_message().append(std::move(s));
}
+TEST_F(AppendTest, LValueStringView)
+{
+ std::string_view s{"asdf"};
+ expect_basic_string_iovec(s.data(), s.size());
+ new_message().append(s);
+}
+
+TEST_F(AppendTest, RValueStringView)
+{
+ std::string_view s{"asdf"};
+ expect_basic_string_iovec(s.data(), s.size());
+ new_message().append(std::string_view{"asdf"});
+}
+
TEST_F(AppendTest, ObjectPath)
{
sdbusplus::message::object_path o{"/asdf"};