metadata 0.2.0
Modern C++23 header-only metadata container (JSON-like)
Loading...
Searching...
No Matches
json.hpp
1#pragma once
2
3#include <nlohmann/json.hpp>
4
5#include <md/error.hpp>
6#include <md/object.hpp>
7#include <md/value.hpp>
8
9#include <cstdint>
10#include <string>
11#include <utility>
12
13namespace md {
14
15namespace detail {
16
17inline void to_nlohmann(nlohmann::json& j, const Value& v);
18
19inline void to_nlohmann(nlohmann::json& j, const Array& a) {
20 j = nlohmann::json::array();
21 for (const auto& el : a) {
22 nlohmann::json sub;
23 to_nlohmann(sub, el);
24 j.push_back(std::move(sub));
25 }
26}
27
28inline void to_nlohmann(nlohmann::json& j, const Object& o) {
29 j = nlohmann::json::object();
30 for (const auto& [k, val] : o) {
31 nlohmann::json sub;
32 to_nlohmann(sub, val);
33 j[k] = std::move(sub);
34 }
35}
36
37inline void to_nlohmann(nlohmann::json& j, const Value& v) {
38 if (v.is_null()) {
39 j = nullptr;
40 } else if (const auto* pb = v.as_bool_if()) {
41 j = *pb;
42 } else if (const auto* pi = v.as_int_if()) {
43 j = *pi;
44 } else if (const auto* pu = v.as_uint_if()) {
45 j = *pu;
46 } else if (const auto* pf = v.as_float_if()) {
47 j = *pf;
48 } else if (const auto* pd = v.as_double_if()) {
49 j = *pd;
50 } else if (const auto* ps = v.as_string_if()) {
51 j = *ps;
52 } else if (const auto* pa = v.as_array_if()) {
53 to_nlohmann(j, *pa);
54 } else if (const auto* po = v.as_object_if()) {
55 to_nlohmann(j, *po);
56 }
57}
58
59inline Value from_nlohmann(const nlohmann::json& j) {
60 switch (j.type()) {
61 case nlohmann::json::value_t::null:
62 return Value{};
63 case nlohmann::json::value_t::boolean:
64 return Value{j.get<bool>()};
65 case nlohmann::json::value_t::number_unsigned:
66 return Value{j.get<std::uint64_t>()};
67 case nlohmann::json::value_t::number_integer:
68 return Value{j.get<std::int64_t>()};
69 case nlohmann::json::value_t::number_float:
70 return Value{j.get<double>()};
71 case nlohmann::json::value_t::string:
72 return Value{j.get<std::string>()};
73 case nlohmann::json::value_t::array: {
74 Array a;
75 a.reserve(j.size());
76 for (const auto& el : j) {
77 a.emplace_back(from_nlohmann(el));
78 }
79 return Value{std::move(a)};
80 }
81 case nlohmann::json::value_t::object: {
82 Object o;
83 o.reserve(j.size());
84 for (auto it = j.begin(); it != j.end(); ++it) {
85 o.insert_or_assign(it.key(), from_nlohmann(it.value()));
86 }
87 return Value{std::move(o)};
88 }
89 default:
90 throw type_error("md::from_json: unsupported nlohmann value type");
91 }
92}
93
94} // namespace detail
95
97inline void to_json(nlohmann::json& j, const Value& v) {
98 detail::to_nlohmann(j, v);
99}
101inline void from_json(const nlohmann::json& j, Value& v) {
102 v = detail::from_nlohmann(j);
103}
104
106inline void to_json(nlohmann::json& j, const Object& o) {
107 detail::to_nlohmann(j, o);
108}
111inline void from_json(const nlohmann::json& j, Object& o) {
112 Value v = detail::from_nlohmann(j);
113 if (auto* p = v.as_object_if()) {
114 o = std::move(*p);
115 } else {
116 throw type_error("md::from_json(Object): JSON value is not an object");
117 }
118}
119
120// Convenience non-ADL forms — slightly nicer at call sites that already use
121// `md::to_json(x)` / `md::from_json(j)`.
123[[nodiscard]] inline nlohmann::json to_json(const Value& v) {
124 nlohmann::json j;
125 detail::to_nlohmann(j, v);
126 return j;
127}
129[[nodiscard]] inline nlohmann::json to_json(const Object& o) {
130 nlohmann::json j;
131 detail::to_nlohmann(j, o);
132 return j;
133}
135[[nodiscard]] inline Value from_json(const nlohmann::json& j) {
136 return detail::from_nlohmann(j);
137}
138
139} // namespace md