Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DRY definition of JSON representation of a c++ class #1459

Closed
madmongo1 opened this issue Jan 27, 2019 · 1 comment
Closed

Implement DRY definition of JSON representation of a c++ class #1459

madmongo1 opened this issue Jan 27, 2019 · 1 comment
Labels
state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated

Comments

@madmongo1
Copy link

madmongo1 commented Jan 27, 2019

  • Describe the feature in as much detail as possible.

At present, in order to provide the ability to round-trip a c++ object to JSON and back, I must write both to_json and from_json, repeating the names of the elements of the corresponding JSON object.

In order to improve this situation I have quickly built a prototype scheme, with an interface loosely modeled on the boost.serialization idea of an Archive and overloading the operator &.

  • Include sample usage where appropriate.

Code follows:

  struct json_write_archive
  {
    json_write_archive(json &target)
    : target_ { target }
    {
    }

    template < class Name, class Arg >
    auto operator&(std::tuple< Name, const Arg & > nvp) -> json_write_archive &
    {
      auto &[name, value] = nvp;
      target_[name]       = value;
      return *this;
    }

    json &target_;
  };

  struct json_read_archive
  {
    json_read_archive(json const &source)
    : source_ { source }
    {
    }

    template < class Name, class Arg >
    auto operator&(std::tuple< Name, Arg & > nvp) -> json_read_archive &
    {
      auto &[name, value] = nvp;
      set_if_present(value, source_, name);
      return *this;
    }

    json const &source_;
  };

  template < class Derived >
  struct json_archivable
  {
    friend auto to_json(json &archive_base, json_archivable const &source) -> void
    {
      archive_base = json::object();
      auto archive = json_write_archive(archive_base);
      Derived::json_serialise(archive, static_cast< Derived const & >(source));
    }

    friend auto from_json(json const &source, json_archivable &target) -> void
    {
      auto archive = json_read_archive(source);
      Derived::json_serialise(archive, static_cast< Derived & >(target));
    }

    template < class Name, class Value >
    static auto nvp(Name name, Value &value)
    {
      return std::tuple< Name, Value & > { name, value };
    }
  };

example of use:

  struct some_settings
  : json_archivable< some_settings > // this is the important bit
  {

    // implement json_archivable
    template < class Archive, class Self >
    static void json_serialise(Archive &ar, Self &self)
    {
      ar & nvp("rateLimit", self.rate_limit);    // the nvp template function ties the name to the value
      ar & nvp("optionA", self.option_a);
      ar & nvp("optionB", self.option_b);
      ar & nvp("optionC", self.option_c);
    }

    byte_count rate_limit { 100_gb };     // another JSON-enabled class
    double     option_a { 1.0 };
    double     option_b { 3.0 };
    double     option_c { 100.0 };
  };

my particular implementation of set_if_present is as follows:

  template < class T >
  void set_if_present(T &target, json const &source, std::string_view key)
  try
  {
    auto i = source.find(key);
    if (i != source.end())
    {
      target = i->get< T >();   //      i->get_to(target);
    }
  }
  catch (...)
  {
    std::throw_with_nested(std::invalid_argument("key"));
  }

This allows a permissive interpretation of JSON data. This could be a customisation point if people need a different behaviour.

@stale
Copy link

stale bot commented Feb 26, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated label Feb 26, 2019
@stale stale bot closed this as completed Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated
Projects
None yet
Development

No branches or pull requests

1 participant