1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-22 07:42:37 +00:00

feat: support the JSON null type in tr_variant (#7255)

This commit is contained in:
Yat Ho 2024-12-16 06:50:19 +08:00 committed by GitHub
parent 5c714a5599
commit 5a05b37838
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 15 deletions

View file

@ -277,6 +277,11 @@ namespace to_string_helpers
{ {
using OutBuf = libtransmission::StackBuffer<1024U * 8U, std::byte>; using OutBuf = libtransmission::StackBuffer<1024U * 8U, std::byte>;
void saveNullFunc(tr_variant const& /*var*/, std::nullptr_t /*val*/, void* vout)
{
static_cast<OutBuf*>(vout)->add("0:"sv);
}
void saveIntFunc(tr_variant const& /*var*/, int64_t const val, void* vout) void saveIntFunc(tr_variant const& /*var*/, int64_t const val, void* vout)
{ {
auto out = static_cast<OutBuf*>(vout); auto out = static_cast<OutBuf*>(vout);
@ -338,6 +343,7 @@ std::string tr_variant_serde::to_benc_string(tr_variant const& var)
using namespace to_string_helpers; using namespace to_string_helpers;
static auto constexpr Funcs = WalkFuncs{ static auto constexpr Funcs = WalkFuncs{
saveNullFunc, //
saveIntFunc, // saveIntFunc, //
saveBoolFunc, // saveBoolFunc, //
saveRealFunc, // saveRealFunc, //

View file

@ -50,7 +50,7 @@ struct json_to_variant_handler : public rapidjson::BaseReaderHandler<>
bool Null() bool Null()
{ {
*get_leaf() = tr_variant::unmanaged_string(""); *get_leaf() = nullptr;
return true; return true;
} }
@ -311,6 +311,11 @@ private:
using writer_var_t = std::variant<rapidjson::Writer<string_output_stream>, rapidjson::PrettyWriter<string_output_stream>>; using writer_var_t = std::variant<rapidjson::Writer<string_output_stream>, rapidjson::PrettyWriter<string_output_stream>>;
void jsonNullFunc(tr_variant const& /*var*/, std::nullptr_t /*val*/, void* vdata)
{
std::visit([](auto&& writer) { writer.Null(); }, *static_cast<writer_var_t*>(vdata));
}
void jsonIntFunc(tr_variant const& /*var*/, int64_t const val, void* vdata) void jsonIntFunc(tr_variant const& /*var*/, int64_t const val, void* vdata)
{ {
std::visit([val](auto&& writer) { writer.Int64(val); }, *static_cast<writer_var_t*>(vdata)); std::visit([val](auto&& writer) { writer.Int64(val); }, *static_cast<writer_var_t*>(vdata));
@ -363,6 +368,7 @@ std::string tr_variant_serde::to_json_string(tr_variant const& var) const
using namespace to_string_helpers; using namespace to_string_helpers;
static auto constexpr Funcs = WalkFuncs{ static auto constexpr Funcs = WalkFuncs{
jsonNullFunc, //
jsonIntFunc, // jsonIntFunc, //
jsonBoolFunc, // jsonBoolFunc, //
jsonRealFunc, // jsonRealFunc, //

View file

@ -208,6 +208,10 @@ void tr_variant::Merge::operator()(std::monostate const& src)
{ {
tgt_ = src; tgt_ = src;
} }
void tr_variant::Merge::operator()(std::nullptr_t const& src)
{
tgt_ = src;
}
void tr_variant::Merge::operator()(bool const& src) void tr_variant::Merge::operator()(bool const& src)
{ {
tgt_ = src; tgt_ = src;
@ -761,6 +765,10 @@ void tr_variant_serde::walk(tr_variant const& top, WalkFuncs const& walk_funcs,
switch (variant_index(v)) switch (variant_index(v))
{ {
case tr_variant::NullIndex:
walk_funcs.null_func(*v, *v->get_if<tr_variant::NullIndex>(), user_data);
break;
case tr_variant::BoolIndex: case tr_variant::BoolIndex:
walk_funcs.bool_func(*v, *v->get_if<tr_variant::BoolIndex>(), user_data); walk_funcs.bool_func(*v, *v->get_if<tr_variant::BoolIndex>(), user_data);
break; break;

View file

@ -30,15 +30,16 @@
struct tr_variant struct tr_variant
{ {
public: public:
enum Type : size_t enum Type : uint8_t
{ {
NoneIndex = 0, NoneIndex,
BoolIndex = 1, NullIndex,
IntIndex = 2, BoolIndex,
DoubleIndex = 3, IntIndex,
StringIndex = 4, DoubleIndex,
VectorIndex = 5, StringIndex,
MapIndex = 6 VectorIndex,
MapIndex
}; };
using Vector = std::vector<tr_variant>; using Vector = std::vector<tr_variant>;
@ -239,7 +240,11 @@ public:
template<typename Val> template<typename Val>
tr_variant& operator=(Val value) tr_variant& operator=(Val value)
{ {
if constexpr (std::is_same_v<Val, std::string_view>) if constexpr (std::is_same_v<Val, std::nullptr_t>)
{
val_.emplace<std::nullptr_t>(value);
}
else if constexpr (std::is_same_v<Val, std::string_view>)
{ {
val_.emplace<StringHolder>(std::string{ value }); val_.emplace<StringHolder>(std::string{ value });
} }
@ -392,6 +397,7 @@ private:
public: public:
explicit Merge(tr_variant& tgt); explicit Merge(tr_variant& tgt);
void operator()(std::monostate const& src); void operator()(std::monostate const& src);
void operator()(std::nullptr_t const& src);
void operator()(bool const& src); void operator()(bool const& src);
void operator()(int64_t const& src); void operator()(int64_t const& src);
void operator()(double const& src); void operator()(double const& src);
@ -403,7 +409,7 @@ private:
tr_variant& tgt_; tr_variant& tgt_;
}; };
std::variant<std::monostate, bool, int64_t, double, StringHolder, Vector, Map> val_; std::variant<std::monostate, std::nullptr_t, bool, int64_t, double, StringHolder, Vector, Map> val_;
}; };
template<> template<>
@ -567,6 +573,7 @@ private:
struct WalkFuncs struct WalkFuncs
{ {
void (*null_func)(tr_variant const& var, std::nullptr_t val, void* user_data);
void (*int_func)(tr_variant const& var, int64_t val, void* user_data); void (*int_func)(tr_variant const& var, int64_t val, void* user_data);
void (*bool_func)(tr_variant const& var, bool val, void* user_data); void (*bool_func)(tr_variant const& var, bool val, void* user_data);
void (*double_func)(tr_variant const& var, double val, void* user_data); void (*double_func)(tr_variant const& var, double val, void* user_data);

View file

@ -61,7 +61,23 @@ TEST_P(JSONTest, testElements)
" \"null\": null }" " \"null\": null }"
}; };
auto const var = tr_variant_serde::json().inplace().parse(In).value_or(tr_variant{}); // Same as In, just formatted differently
static auto constexpr Out = std::string_view{
// clang-format off
"{"
"\"escaped\":\"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\","
"\"false\":false,"
"\"float\":6.5,"
"\"int\":5,"
"\"null\":null,"
"\"string\":\"hello world\","
"\"true\":true"
"}"
// clang-format on
};
auto serde = tr_variant_serde::json().inplace().compact();
auto var = serde.parse(In).value_or(tr_variant{});
auto const* const map = var.get_if<tr_variant::Map>(); auto const* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr); ASSERT_NE(map, nullptr);
@ -89,9 +105,10 @@ TEST_P(JSONTest, testElements)
ASSERT_TRUE(b); ASSERT_TRUE(b);
EXPECT_FALSE(*b); EXPECT_FALSE(*b);
sv = map->value_if<std::string_view>(tr_quark_new("null"sv)); auto n = map->value_if<std::nullptr_t>(tr_quark_new("null"sv));
ASSERT_TRUE(sv); EXPECT_TRUE(n);
EXPECT_EQ(""sv, *sv);
EXPECT_EQ(serde.to_string(var), Out);
} }
TEST_P(JSONTest, testUtf8) TEST_P(JSONTest, testUtf8)