Skip to content

Commit 39dbd6a

Browse files
committed
feat: add support for dumping variant to string
1 parent 9f3e89e commit 39dbd6a

4 files changed

Lines changed: 93 additions & 1 deletion

File tree

include/sdbus-c++/Message.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,15 @@ namespace sdbus {
228228
void seal();
229229
void rewind(bool complete);
230230

231+
enum class DumpFlags : uint64_t
232+
{
233+
Default = 0ULL,
234+
WithHeader = 1ULL << 0,
235+
SubtreeOnly = 1ULL << 1,
236+
SubtreeOnlyWithHeader = WithHeader | SubtreeOnly
237+
};
238+
[[nodiscard]] std::string dumpToString(DumpFlags flags) const;
239+
231240
pid_t getCredsPid() const;
232241
uid_t getCredsUid() const;
233242
uid_t getCredsEuid() const;
@@ -260,7 +269,6 @@ namespace sdbus {
260269

261270
friend Factory;
262271

263-
264272
void* msg_{};
265273
internal::IConnection* connection_{};
266274
mutable bool ok_{true};

include/sdbus-c++/Types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ namespace sdbus {
103103
return val;
104104
}
105105

106+
[[nodiscard]] std::string dumpToString() const
107+
{
108+
msg_.rewind(false);
109+
110+
return msg_.dumpToString(Message::DumpFlags::SubtreeOnly);
111+
}
112+
106113
// Only allow conversion operator for true D-Bus type representations in C++
107114
// NOLINTNEXTLINE(modernize-use-constraints): TODO for future: Use `requires signature_of<_ValueType>::is_valid` (when we stop supporting C++17 in public API)
108115
template <typename ValueType, typename = std::enable_if_t<signature_of<ValueType>::is_valid>>

src/Message.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#include <cassert>
3838
#include <cstdint> // int16_t, uint64_t, ...
39+
#include <cstdio>
3940
#include <cstdlib> // atexit
4041
#include <cstring>
4142
#include <string>
@@ -628,6 +629,30 @@ void Message::rewind(bool complete)
628629
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
629630
}
630631

632+
std::string Message::dumpToString(DumpFlags flags) const
633+
{
634+
#if LIBSYSTEMD_VERSION>=245 && !defined(SDBUS_basu)
635+
char* buffer{};
636+
size_t size{};
637+
638+
FILE* stream = open_memstream(&buffer, &size);
639+
SDBUS_THROW_ERROR_IF(!stream, "Failed to open memory stream", errno);
640+
641+
SCOPE_EXIT{ free(buffer); };
642+
SCOPE_EXIT{ fclose(stream); };
643+
644+
auto r = sd_bus_message_dump(static_cast<sd_bus_message*>(msg_), stream, static_cast<uint64_t>(flags));
645+
SDBUS_THROW_ERROR_IF(r < 0, "Failed to dump the message", -r);
646+
647+
fflush(stream);
648+
649+
return {buffer, size};
650+
#else
651+
(void)flags;
652+
throw Error(Error::Name{SD_BUS_ERROR_NOT_SUPPORTED}, "Dumping sd-bus message not supported by underlying version of libsystemd");
653+
#endif
654+
}
655+
631656
const char* Message::getInterfaceName() const
632657
{
633658
return sd_bus_message_get_interface(static_cast<sd_bus_message*>(msg_));

tests/unittests/Types_test.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
using ::testing::Eq;
4747
using ::testing::Gt;
48+
using ::testing::HasSubstr;
4849
using namespace std::string_literals;
4950

5051
namespace
@@ -148,6 +149,24 @@ TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
148149
ASSERT_THAT(variant.get<int>(), Eq(value));
149150
}
150151

152+
#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
153+
TEST(ASimpleVariant, CanBeDumpedToAString)
154+
{
155+
const int value = 5;
156+
const sdbus::Variant variant(value);
157+
158+
// This should produce something like:
159+
// VARIANT "i" {
160+
// INT32 5;
161+
// };
162+
const auto str = variant.dumpToString();
163+
164+
EXPECT_THAT(str, ::HasSubstr("VARIANT \"i\""));
165+
EXPECT_THAT(str, ::HasSubstr("INT32"));
166+
EXPECT_THAT(str, ::HasSubstr("5"));
167+
}
168+
#endif // SDBUS_basu
169+
151170
TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
152171
{
153172
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
@@ -158,6 +177,39 @@ TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
158177
ASSERT_THAT(variant.get<ComplexType>(), Eq(value));
159178
}
160179

180+
#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
181+
TEST(AComplexVariant, CanBeDumpedToAString)
182+
{
183+
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
184+
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
185+
const sdbus::Variant variant(value);
186+
187+
// This should produce something like:
188+
// VARIANT "a{ta(sd)}" {
189+
// ARRAY "{ta(sd)}" {
190+
// DICT_ENTRY "ta(sd)" {
191+
// UINT64 84578348354;
192+
// ARRAY "(sd)" {
193+
// STRUCT "sd" {
194+
// STRING "hello";
195+
// DOUBLE 3.14;
196+
// };
197+
// STRUCT "sd" {
198+
// STRING "world";
199+
// DOUBLE 3.14;
200+
// };
201+
// };
202+
// };
203+
// };
204+
// };
205+
const auto str = variant.dumpToString();
206+
207+
EXPECT_THAT(str, ::HasSubstr("VARIANT \"a{ta(sd)}\""));
208+
EXPECT_THAT(str, ::HasSubstr("hello"));
209+
EXPECT_THAT(str, ::HasSubstr("world"));
210+
}
211+
#endif // SDBUS_basu
212+
161213
TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
162214
{
163215
const std::string value{"I am a string"};

0 commit comments

Comments
 (0)