Stiffstream / json_dto

A small header-only library for converting data between json representation and c++ structs
BSD 3-Clause "New" or "Revised" License
149 stars 18 forks source link

magic json serialization #24

Open omartijn opened 9 months ago

omartijn commented 9 months ago

I recently discovered Boost.PFR, which allows a form of reflection on simple aggregates. Reading the field names is, unfortunately, only supported in c++20 (so we couldn't add direct support for it inside json_dto), but I think it's useful enough that it warrants an example, and maybe a mention in the main README. Take the following code:

#include <boost/pfr.hpp>
#include <iostream>
#include <json_dto/pub.hpp>

struct bla {
    int x;
    float y;
    std::string z;
};

template <typename wrapped>
class aggregate {
   public:
    aggregate(wrapped& data) : data{data} {}

    template <typename io_type>
    void json_io(io_type& io) {
        json_io(io,
                std::make_index_sequence<boost::pfr::tuple_size_v<wrapped>>());
    }

   private:
    template <typename io_type, std::size_t... i>
    void json_io(io_type& io, std::index_sequence<i...>) {
        ((io &
          json_dto::mandatory(
              rapidjson::StringRef(boost::pfr::get_name<i, wrapped>().data(),
                                   boost::pfr::get_name<i, wrapped>().size()),
              boost::pfr::get<i>(data))),
         ...);
    }

    wrapped& data;
};

int main() {
    bla x{1, 2.5f, "greetings"};

    auto result = json_dto::to_json(aggregate{x});
    std::cout << result << std::endl;

    bla y{};
    aggregate a{y};
    std::string input{"{\"x\":1,\"y\":2.5,\"z\":\"greetings\"}"};
    json_dto::from_json(input, a);

    assert(x.x == y.x);
    assert(x.y == y.y);
    assert(x.z == y.z);
}

This example highlights (de)serializing structs without manually binding the fields! Simply add a field and it's automatically (de)serialized.