Serialization: Correctly encode structs with no fields
Empty structs were being serialized as `null`, when they should have been serialized as `{}`. This was due to the type inference on the serializer - where no calls to `field()` would result in the default `null` type. To solve this, the `serialize(const void* object, const std::initializer_list<Field>&)` inline helper has been promoted to a virtual function (and renamed to `fields()`). The JSON serializer implementation of this now first sets the object type to `object`, even if there are no fields to serialize. Added test for this. Fixes: #10
This commit is contained in:
parent
3a10d4cabd
commit
cdc19ac4d9
@ -166,6 +166,10 @@ class Serializer {
|
|||||||
// Serializer that should be used to encode the n'th array element's data.
|
// Serializer that should be used to encode the n'th array element's data.
|
||||||
virtual bool array(size_t count, const std::function<bool(Serializer*)>&) = 0;
|
virtual bool array(size_t count, const std::function<bool(Serializer*)>&) = 0;
|
||||||
|
|
||||||
|
// fields() encodes all the provided fields of the given object.
|
||||||
|
virtual bool fields(const void* object,
|
||||||
|
const std::initializer_list<Field>&) = 0;
|
||||||
|
|
||||||
// field() encodes a field to the struct object referenced by this Serializer.
|
// field() encodes a field to the struct object referenced by this Serializer.
|
||||||
// The FieldSerializer will be called with a Serializer used to encode the
|
// The FieldSerializer will be called with a Serializer used to encode the
|
||||||
// field's data.
|
// field's data.
|
||||||
@ -192,10 +196,6 @@ class Serializer {
|
|||||||
template <typename T0, typename... Types>
|
template <typename T0, typename... Types>
|
||||||
inline bool serialize(const dap::variant<T0, Types...>&);
|
inline bool serialize(const dap::variant<T0, Types...>&);
|
||||||
|
|
||||||
// serialize() encodes all the provided fields of the given object.
|
|
||||||
inline bool serialize(const void* object,
|
|
||||||
const std::initializer_list<Field>&);
|
|
||||||
|
|
||||||
// deserialize() encodes the given string.
|
// deserialize() encodes the given string.
|
||||||
inline bool serialize(const char* v);
|
inline bool serialize(const char* v);
|
||||||
|
|
||||||
@ -231,18 +231,6 @@ bool Serializer::serialize(const dap::variant<T0, Types...>& var) {
|
|||||||
return serialize(var.value);
|
return serialize(var.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Serializer::serialize(const void* object,
|
|
||||||
const std::initializer_list<Field>& fields) {
|
|
||||||
for (auto const& f : fields) {
|
|
||||||
if (!field(f.name, [&](Serializer* d) {
|
|
||||||
auto ptr = reinterpret_cast<const uint8_t*>(object) + f.offset;
|
|
||||||
return f.type->serialize(d, ptr);
|
|
||||||
}))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Serializer::serialize(const char* v) {
|
bool Serializer::serialize(const char* v) {
|
||||||
return serialize(std::string(v));
|
return serialize(std::string(v));
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ M member_type(M T::*);
|
|||||||
return d->deserialize(ptr, {__VA_ARGS__}); \
|
return d->deserialize(ptr, {__VA_ARGS__}); \
|
||||||
} \
|
} \
|
||||||
bool serialize(Serializer* s, const void* ptr) const override { \
|
bool serialize(Serializer* s, const void* ptr) const override { \
|
||||||
return s->serialize(ptr, {__VA_ARGS__}); \
|
return s->fields(ptr, {__VA_ARGS__}); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
static TI typeinfo; \
|
static TI typeinfo; \
|
||||||
|
@ -224,6 +224,19 @@ bool Serializer::array(size_t count,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Serializer::fields(const void* object,
|
||||||
|
const std::initializer_list<Field>& fields) {
|
||||||
|
*json = nlohmann::json({}, false, nlohmann::json::value_t::object);
|
||||||
|
for (auto const& f : fields) {
|
||||||
|
if (!field(f.name, [&](dap::Serializer* d) {
|
||||||
|
auto ptr = reinterpret_cast<const uint8_t*>(object) + f.offset;
|
||||||
|
return f.type->serialize(d, ptr);
|
||||||
|
}))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Serializer::field(const std::string& name,
|
bool Serializer::field(const std::string& name,
|
||||||
const std::function<bool(dap::Serializer*)>& cb) {
|
const std::function<bool(dap::Serializer*)>& cb) {
|
||||||
Serializer s(&(*json)[name]);
|
Serializer s(&(*json)[name]);
|
||||||
|
@ -98,6 +98,8 @@ struct Serializer : public dap::Serializer {
|
|||||||
bool serialize(const any& v) override;
|
bool serialize(const any& v) override;
|
||||||
bool array(size_t count,
|
bool array(size_t count,
|
||||||
const std::function<bool(dap::Serializer*)>&) override;
|
const std::function<bool(dap::Serializer*)>&) override;
|
||||||
|
bool fields(const void* object,
|
||||||
|
const std::initializer_list<Field>& fields) override;
|
||||||
bool field(const std::string& name, const FieldSerializer&) override;
|
bool field(const std::string& name, const FieldSerializer&) override;
|
||||||
void remove() override;
|
void remove() override;
|
||||||
|
|
||||||
@ -130,10 +132,6 @@ struct Serializer : public dap::Serializer {
|
|||||||
return dap::Serializer::serialize(v);
|
return dap::Serializer::serialize(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool serialize(const void* o, const std::initializer_list<Field>& f) {
|
|
||||||
return dap::Serializer::serialize(o, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool serialize(const char* v) { return dap::Serializer::serialize(v); }
|
inline bool serialize(const char* v) { return dap::Serializer::serialize(v); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -56,7 +56,9 @@ DAP_STRUCT_TYPEINFO(JSONTestObject,
|
|||||||
DAP_FIELD(o2, "o2"),
|
DAP_FIELD(o2, "o2"),
|
||||||
DAP_FIELD(inner, "inner"));
|
DAP_FIELD(inner, "inner"));
|
||||||
|
|
||||||
TEST(JSONSerializer, Decode) {}
|
struct JSONObjectNoFields {};
|
||||||
|
|
||||||
|
DAP_STRUCT_TYPEINFO(JSONObjectNoFields, "json-object-no-fields");
|
||||||
|
|
||||||
} // namespace dap
|
} // namespace dap
|
||||||
|
|
||||||
@ -91,3 +93,10 @@ TEST(JSONSerializer, SerializeDeserialize) {
|
|||||||
ASSERT_EQ(encoded.o2, decoded.o2);
|
ASSERT_EQ(encoded.o2, decoded.o2);
|
||||||
ASSERT_EQ(encoded.inner.i, decoded.inner.i);
|
ASSERT_EQ(encoded.inner.i, decoded.inner.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(JSONSerializer, SerializeObjectNoFields) {
|
||||||
|
dap::JSONObjectNoFields obj;
|
||||||
|
dap::json::Serializer s;
|
||||||
|
ASSERT_TRUE(s.serialize(obj));
|
||||||
|
ASSERT_EQ(s.dump(), "{}");
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user