diff --git a/common/json.cpp b/common/json.cpp index a40622437b..40cff037c3 100644 --- a/common/json.cpp +++ b/common/json.cpp @@ -82,10 +82,44 @@ common_json_value::common_json_value(const char * val) { common_json_value::common_json_value(const common_json & val) : type(VAL_JSON), val_json(std::make_shared(val)) {} -common_json_value::common_json_value(const std::map & vals) : type(VAL_JSON) { - val_json = std::make_shared(common_json_from_raw(ordered_json(vals))); +template +common_json_value::common_json_value(const std::set & vals) : type(VAL_JSON) { + common_json out = common_json::array(); + + for (const auto & val : vals) { + out.push_back(val); + } + + val_json = std::make_shared(std::move(out)); } +// a set value is usable only for the types below +#define COMMON_JSON_SET(...) template common_json_value::common_json_value(const std::set<__VA_ARGS__> &); + +COMMON_JSON_SET(int) +COMMON_JSON_SET(std::string) + +#undef COMMON_JSON_SET + +template +common_json_value::common_json_value(const std::map & vals) : type(VAL_JSON) { + common_json out = common_json::object(); + + for (const auto & val : vals) { + out.set({ val.first, val.second }); + } + + val_json = std::make_shared(std::move(out)); +} + +// a map value is usable only for the types below +#define COMMON_JSON_MAP(...) template common_json_value::common_json_value(const std::map &); + +COMMON_JSON_MAP(bool) +COMMON_JSON_MAP(std::string) + +#undef COMMON_JSON_MAP + template common_json_value::common_json_value(const std::vector & vals) : type(VAL_JSON) { common_json out = common_json::array(); diff --git a/common/json.h b/common/json.h index bc4b65b031..6f009b2a55 100644 --- a/common/json.h +++ b/common/json.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -59,10 +60,12 @@ struct common_json_value { common_json_value(std::string_view val) : type(VAL_STRING), val_string(val) {} common_json_value(const char * val); common_json_value(const common_json & val); - // becomes an object, so a plain string map can be passed where a JSON value is expected - common_json_value(const std::map & vals); // only for the types instantiated in json.cpp, the rest fails at link time template common_json_value(const std::vector & vals); + // a set becomes an array, in the set's own order + template common_json_value(const std::set & vals); + // a map becomes an object, keyed in the map's own order + template common_json_value(const std::map & vals); // nested object, e.g. {"fn", {{"name", "x"}}} common_json_value(std::initializer_list items); @@ -93,6 +96,26 @@ struct common_json_item { key(std::move(key)), val(items) {} }; +// the types common_json_value holds on its own. anything else reaches its +// common_json ctor, which builds a common_json again and never stops +template struct common_json_is_value : std::integral_constant::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value> {}; + +template +struct common_json_is_value> : std::true_type {}; + +template +struct common_json_is_value> : std::true_type {}; + +template +struct common_json_is_value> : std::true_type {}; + class common_json { public: common_json(); @@ -107,7 +130,10 @@ class common_json { // one step, so that "abc" or a vector can go straight into a common_json template ::type, common_json>::value && !std::is_same::type, common_json_value>::value, int>::type = 0> - common_json(T && val) : common_json(common_json_value(std::forward(val))) {} + common_json(T && val) : common_json(common_json_value(std::forward(val))) { + static_assert(common_json_is_value::type>::value, + "no common_json_value ctor holds this type, add one instead of letting it recurse"); + } // by value, same as the backing library: the right side is copied before the // left side can invalidate it, e.g. msg["a"] = msg.at("b") where "a" is new