diff --git a/src/libutil-test-support/include/nix/util/tests/json-characterization.hh b/src/libutil-test-support/include/nix/util/tests/json-characterization.hh index bd70ba830..6db32c4b6 100644 --- a/src/libutil-test-support/include/nix/util/tests/json-characterization.hh +++ b/src/libutil-test-support/include/nix/util/tests/json-characterization.hh @@ -5,6 +5,7 @@ #include #include "nix/util/types.hh" +#include "nix/util/ref.hh" #include "nix/util/file-system.hh" #include "nix/util/tests/characterization.hh" @@ -39,6 +40,25 @@ void writeJsonTest(CharacterizationTest & test, PathView testStem, const T & val [](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); } +/** + * Specialization for when we need to do "JSON -> `ref`" in one + * direction, but "`const T &` -> JSON" in the other direction. + * + * We can't just return `const T &`, but it would be wasteful to + * requires a `const ref &` double indirection (and mandatory shared + * pointer), so we break the symmetry as the best remaining option. + */ +template +void writeJsonTest(CharacterizationTest & test, PathView testStem, const ref & value) +{ + using namespace nlohmann; + test.writeTest( + Path{testStem} + ".json", + [&]() -> json { return static_cast(*value); }, + [](const auto & file) { return json::parse(readFile(file)); }, + [](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); +} + /** * Golden test in the middle of something */ diff --git a/src/libutil/include/nix/util/json-impls.hh b/src/libutil/include/nix/util/json-impls.hh index b55716a6d..26a94472f 100644 --- a/src/libutil/include/nix/util/json-impls.hh +++ b/src/libutil/include/nix/util/json-impls.hh @@ -6,18 +6,30 @@ #include "nix/util/experimental-features.hh" // Following https://github.com/nlohmann/json#how-can-i-use-get-for-non-default-constructiblenon-copyable-types +#define JSON_IMPL_INNER_TO(TYPE) \ + struct adl_serializer \ + { \ + static void to_json(json & json, const TYPE & t); \ + } + +#define JSON_IMPL_INNER_FROM(TYPE) \ + struct adl_serializer \ + { \ + static TYPE from_json(const json & json); \ + } + #define JSON_IMPL_INNER(TYPE) \ struct adl_serializer \ { \ static TYPE from_json(const json & json); \ static void to_json(json & json, const TYPE & t); \ - }; + } -#define JSON_IMPL(TYPE) \ - namespace nlohmann { \ - using namespace nix; \ - template<> \ - JSON_IMPL_INNER(TYPE) \ +#define JSON_IMPL(TYPE) \ + namespace nlohmann { \ + using namespace nix; \ + template<> \ + JSON_IMPL_INNER(TYPE); \ } #define JSON_IMPL_WITH_XP_FEATURES(TYPE) \ diff --git a/src/libutil/include/nix/util/memory-source-accessor.hh b/src/libutil/include/nix/util/memory-source-accessor.hh index 933af600a..fc00f34d9 100644 --- a/src/libutil/include/nix/util/memory-source-accessor.hh +++ b/src/libutil/include/nix/util/memory-source-accessor.hh @@ -188,23 +188,23 @@ using namespace nix; #define ARG fso::Regular template -JSON_IMPL_INNER(ARG) +JSON_IMPL_INNER(ARG); #undef ARG #define ARG fso::DirectoryT template -JSON_IMPL_INNER(ARG) +JSON_IMPL_INNER(ARG); #undef ARG template<> -JSON_IMPL_INNER(fso::Symlink) +JSON_IMPL_INNER(fso::Symlink); template<> -JSON_IMPL_INNER(fso::Opaque) +JSON_IMPL_INNER(fso::Opaque); #define ARG fso::VariantT template -JSON_IMPL_INNER(ARG) +JSON_IMPL_INNER(ARG); #undef ARG } // namespace nlohmann