#pragma once
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include <optional>

#define ENROLL_COMPONENT(COMPONENT, ...)                         \
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__);  \
    template <> struct NameOf<COMPONENT> {                       \
      static constexpr const char *name = #COMPONENT;            \
    };

// partial specialization (full specialization works too)
namespace nlohmann {
  template <typename T>
    struct adl_serializer<std::optional<T>> {
      static void to_json(json& j, const std::optional<T>& opt) {
        if (opt == std::nullopt) {
          j = nullptr;
        } else {
          j = *opt; // this will call adl_serializer<T>::to_json which will
          // find the free function to_json in T's namespace!
        }
      }

      static void from_json(const json& j, std::optional<T>& opt) {
        if (j.is_null() || j == false) {
          opt = std::nullopt;
        } else {
          opt = std::make_optional<T>(j.template get<T>());
          // same as above, but with adl_serializer<T>::from_json
        }
      }
    };
}