diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2023-06-16 15:19:14 -0400 |
---|---|---|
committer | John Ericson <John.Ericson@Obsidian.Systems> | 2023-06-18 23:31:10 -0400 |
commit | c8825e9d8c3fa802811f3829d055e3ef9aae90e2 (patch) | |
tree | 590b8bf2103bb7e09d2fb72c930fe5542ee3d36d /src/libutil/json-utils.hh | |
parent | 3b0d8fd796336318ce03c8ee90cd40ebb65fb032 (diff) |
Create nlohmann serializers for `std::optional` and use
This is somewhat tricky.
Diffstat (limited to 'src/libutil/json-utils.hh')
-rw-r--r-- | src/libutil/json-utils.hh | 78 |
1 files changed, 67 insertions, 11 deletions
diff --git a/src/libutil/json-utils.hh b/src/libutil/json-utils.hh index eb00e954f..5e63c1af4 100644 --- a/src/libutil/json-utils.hh +++ b/src/libutil/json-utils.hh @@ -2,21 +2,77 @@ ///@file #include <nlohmann/json.hpp> +#include <list> namespace nix { -const nlohmann::json * get(const nlohmann::json & map, const std::string & key) -{ - auto i = map.find(key); - if (i == map.end()) return nullptr; - return &*i; -} +const nlohmann::json * get(const nlohmann::json & map, const std::string & key); + +nlohmann::json * get(nlohmann::json & map, const std::string & key); + +/** + * For `adl_serializer<std::optional<T>>` below, we need to track what + * types are not already using `null`. Only for them can we use `null` + * to represent `std::nullopt`. + */ +template<typename T> +struct json_avoids_null; + +/** + * Handle numbers in default impl + */ +template<typename T> +struct json_avoids_null : std::bool_constant<std::is_integral<T>::value> {}; + +template<> +struct json_avoids_null<std::nullptr_t> : std::false_type {}; + +template<> +struct json_avoids_null<bool> : std::true_type {}; + +template<> +struct json_avoids_null<std::string> : std::true_type {}; + +template<typename T> +struct json_avoids_null<std::vector<T>> : std::true_type {}; + +template<typename T> +struct json_avoids_null<std::list<T>> : std::true_type {}; + +template<typename K, typename V> +struct json_avoids_null<std::map<K, V>> : std::true_type {}; -nlohmann::json * get(nlohmann::json & map, const std::string & key) -{ - auto i = map.find(key); - if (i == map.end()) return nullptr; - return &*i; } +namespace nlohmann { + +/** + * This "instance" is widely requested, see + * https://github.com/nlohmann/json/issues/1749, but momentum has stalled + * out. Writing there here in Nix as a stop-gap. + * + * We need to make sure the underlying type does not use `null` for this to + * round trip. We do that with a static assert. + */ +template<typename T> +struct adl_serializer<std::optional<T>> { + static std::optional<T> from_json(const json & json) { + static_assert( + nix::json_avoids_null<T>::value, + "null is already in use for underlying type's JSON"); + return json.is_null() + ? std::nullopt + : std::optional { adl_serializer<T>::from_json(json) }; + } + static void to_json(json & json, std::optional<T> t) { + static_assert( + nix::json_avoids_null<T>::value, + "null is already in use for underlying type's JSON"); + if (t) + adl_serializer<T>::to_json(json, *t); + else + json = nullptr; + } +}; + } |