1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-27 12:41:15 +02:00

Create nlohmann serializers for std::optional and use

This is somewhat tricky.
This commit is contained in:
John Ericson 2023-06-16 15:19:14 -04:00
parent 3b0d8fd796
commit c8825e9d8c
4 changed files with 97 additions and 25 deletions

View file

@ -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)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
return &*i;
}
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 {};
}
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;
}
};
}