Different JSONs - the same class #550
Replies: 4 comments
-
Is otherwise you could do something like struct Thing_a : Thing {};
struct Thing_b : Thing {};
template <>
struct glz::meta<Thing_a> {
static constexpr auto value{ glz::object("a", &Thing_a::a) };
};
glz::write(Thing_a{.a="foo"});
// etc |
Beta Was this translation helpful? Give feedback.
-
It seems like this is particularly useful for writing JSON, as reading JSON keys are already optional. Have you looked at auto meta1 = glz::obj("a", &T::a);
glz::write_json(meta1, buf);
auto meta2 = glz::obj("b", &T::b);
glz::write_json(meta2, buf); That should give you the behavior you want. |
Beta Was this translation helpful? Give feedback.
-
@Bolderaysky, I totally agree with the suggestions by @jbbjarnason and @stephenberry. I do what you're requesting in my own code, too. Shown below is a complete example of how one could create these wrappers using inheritance or composition. The C++ interfaces were not tailored, but I hope this is useful to you and others for the representation portion. #include <cassert>
#include <cstdint>
#include <string>
#include <glaze/core/common.hpp>
#include <glaze/core/meta.hpp>
#include <glaze/json/write.hpp>
struct Thing {
std::string a{};
std::uint64_t b{};
};
namespace inherit {
struct Internal_thing final : Thing {
struct glaze {
static constexpr auto value = glz::object(&Thing::a, &Thing::b);
};
};
struct Freemium_thing final : Thing {
struct glaze {
static constexpr auto value = glz::object(&Thing::b);
};
};
struct Paid_thing final : Thing {
struct glaze {
static constexpr auto value = glz::object(&Thing::a);
};
};
} // namespace inherit
namespace compose {
struct Internal_thing {
Thing t{}; // could be a ref if Internal_thing is only for interface
struct glaze {
static constexpr auto value = glz::object(
"a", [](auto &&self) -> decltype(auto) { return self.t.a; }, //
"b", [](auto &&self) -> decltype(auto) { return self.t.b; });
};
};
struct Freemium_thing {
Thing t{}; // could be a ref if Fremium_thing is only for interface
struct glaze {
static constexpr auto value = glz::object(
"b", [](auto &&self) -> decltype(auto) { return self.t.b; });
};
};
struct Paid_thing {
Thing t{}; // could be a ref if Paid_thing is only for interface
struct glaze {
static constexpr auto value = glz::object(
"a", [](auto &&self) -> decltype(auto) { return self.t.a; });
};
};
} // namespace compose
int main() {
{
// I know exactly what interface I want, and I have an instance of that...
{
// with inherited versions:
const inherit::Internal_thing internal_thing{"one", 2};
const inherit::Freemium_thing freemium_thing{"one", 2};
const inherit::Paid_thing paid_thing{"one", 2};
assert(glz::write_json(internal_thing) == R"({"a":"one","b":2})");
assert(glz::write_json(freemium_thing) == R"({"b":2})");
assert(glz::write_json(paid_thing) == R"({"a":"one"})");
}
{
// with composed versions:
const compose::Internal_thing internal_thing{{"one", 2}};
const compose::Freemium_thing freemium_thing{{"one", 2}};
const compose::Paid_thing paid_thing{{"one", 2}};
assert(glz::write_json(internal_thing) == R"({"a":"one","b":2})");
assert(glz::write_json(freemium_thing) == R"({"b":2})");
assert(glz::write_json(paid_thing) == R"({"a":"one"})");
}
}
// I already have a Thing and I want to present it with a given interface...
{
{
// with inherited versions (via construction):
const Thing given{"one", 2};
const compose::Internal_thing internal_thing{given};
const compose::Freemium_thing freemium_thing{given};
const compose::Paid_thing paid_thing{given};
assert(glz::write_json(internal_thing) == R"({"a":"one","b":2})");
assert(glz::write_json(freemium_thing) == R"({"b":2})");
assert(glz::write_json(paid_thing) == R"({"a":"one"})");
}
{
// with inherited versions (via casting (less type-safe)):
const Thing given{"one", 2};
const auto &internal_thing =
static_cast<const inherit::Internal_thing &>(given);
const auto &freemium_thing =
static_cast<const inherit::Freemium_thing &>(given);
const auto &paid_thing = static_cast<const inherit::Paid_thing &>(given);
assert(glz::write_json(internal_thing) == R"({"a":"one","b":2})");
assert(glz::write_json(freemium_thing) == R"({"b":2})");
assert(glz::write_json(paid_thing) == R"({"a":"one"})");
}
{
// with composed versions:
const Thing given{"one", 2};
const compose::Internal_thing internal_thing{given};
const compose::Freemium_thing freemium_thing{given};
const compose::Paid_thing paid_thing{given};
assert(glz::write_json(internal_thing) == R"({"a":"one","b":2})");
assert(glz::write_json(freemium_thing) == R"({"b":2})");
assert(glz::write_json(paid_thing) == R"({"a":"one"})");
}
}
}
|
Beta Was this translation helpful? Give feedback.
-
Yeah, @stephenberry and @justend29 both right, Closing as solved. |
Beta Was this translation helpful? Give feedback.
-
Sometimes it's useful to generate json with different fields from the same class/structure, for example:
As far as I see, it's not currently possible to generate different JSONs from the same class/object. If it's not possible, how it potentially could look:
If user didn't specify struct with metadata explicitly,
glz::meta
specialization or inlinestruct glaze
can be used as before. This way, it would easily allow to serialize or deserialize different interfaces or parts of interfaces with the same class, making glaze much more flexibleBeta Was this translation helpful? Give feedback.
All reactions