dimval 0.2.0
Modern C++23 header-only library of dimensional values (units, measures, ranges)
Loading...
Searching...
No Matches
json_nlohmann.hpp
Go to the documentation of this file.
1#pragma once
2
23
24#if !defined(DIMVAL_WITH_NLOHMANN_JSON)
25#if __has_include(<nlohmann/json.hpp>)
26#define DIMVAL_WITH_NLOHMANN_JSON 1
27#else
28#define DIMVAL_WITH_NLOHMANN_JSON 0
29#endif
30#endif
31
32#if DIMVAL_WITH_NLOHMANN_JSON
33
34#include <dimval/measure.hpp>
35#include <dimval/range.hpp>
36#include <dimval/traits.hpp>
37#include <dimval/unit.hpp>
38
39#include <nlohmann/json.hpp>
40
41#include <commons/json.hpp>
42
43#include <string>
44
45namespace dimval {
46
47template <UnitLike U, NumericValue T>
48inline void to_json(::nlohmann::json& j, const UnitValue<U, T>& v) {
49 constexpr auto d = U::descriptor();
50 j = ::nlohmann::json{{"u", d.id}, {"v", v.v}};
51}
52
53template <UnitLike U, NumericValue T>
54inline void from_json(const ::nlohmann::json& j, UnitValue<U, T>& v) {
55 constexpr auto d = U::descriptor();
56 const auto id = j.at("u").get<std::string>();
57 if (id != d.id) {
58 throw ::nlohmann::detail::other_error::create(
59 502,
60 std::string{"dimval: unit mismatch: expected '"} + std::string{d.id} + "', got '" + id +
61 "'",
62 &j);
63 }
64 v.v = j.at("v").get<T>();
65}
66
67template <MeasureLike M, NumericValue T>
68inline void to_json(::nlohmann::json& j, const MeasureValue<M, T>& v) {
69 constexpr auto md = M::descriptor();
70 using unit_t = M::base_unit_t;
71 constexpr auto ud = unit_t::descriptor();
72 j = ::nlohmann::json{{"m", md.id}, {"u", ud.id}, {"v", v.v}};
73}
74
75template <MeasureLike M, NumericValue T>
76inline void from_json(const ::nlohmann::json& j, MeasureValue<M, T>& v) {
77 constexpr auto md = M::descriptor();
78 using unit_t = M::base_unit_t;
79 constexpr auto ud = unit_t::descriptor();
80 const auto mid = j.at("m").get<std::string>();
81 if (mid != md.id) {
82 throw ::nlohmann::detail::other_error::create(
83 502,
84 std::string{"dimval: measure mismatch: expected '"} + std::string{md.id} + "', got '" +
85 mid + "'",
86 &j);
87 }
88 if (const auto it = j.find("u"); it != j.end()) {
89 const auto uid = it->get<std::string>();
90 if (uid != ud.id) {
91 throw ::nlohmann::detail::other_error::create(
92 502,
93 std::string{"dimval: unit mismatch: expected '"} + std::string{ud.id} + "', got '" +
94 uid + "'",
95 &j);
96 }
97 }
98 v.v = j.at("v").get<T>();
99}
100
101template <UnitLike U, NumericValue T>
102inline void to_json(::nlohmann::json& j, const UnitRangeValue<U, T>& r) {
103 constexpr auto d = U::descriptor();
104 j = ::nlohmann::json{
105 {"u", d.id},
106 {"min", r.min().v},
107 {"max", r.max().v},
108 {"mi", r.inclusion().lower == Bound::Inclusive},
109 {"xi", r.inclusion().upper == Bound::Inclusive},
110 };
111}
112
113template <UnitLike U, NumericValue T>
114inline void from_json(const ::nlohmann::json& j, UnitRangeValue<U, T>& r) {
115 constexpr auto d = U::descriptor();
116 const auto id = j.at("u").get<std::string>();
117 if (id != d.id) {
118 throw ::nlohmann::detail::other_error::create(
119 502,
120 std::string{"dimval: unit mismatch: expected '"} + std::string{d.id} + "', got '" + id +
121 "'",
122 &j);
123 }
124 const auto lo = j.at("min").get<T>();
125 const auto hi = j.at("max").get<T>();
126 RangeInclusion inc{
127 j.value("mi", true) ? Bound::Inclusive : Bound::Exclusive,
128 j.value("xi", true) ? Bound::Inclusive : Bound::Exclusive,
129 };
130 auto built = UnitRangeValue<U, T>::make(UnitValue<U, T>{lo}, UnitValue<U, T>{hi}, inc);
131 if (!built) {
132 throw ::nlohmann::detail::other_error::create(
133 502, std::string{"dimval: invalid range: "} + built.error().message, &j);
134 }
135 r = *built;
136}
137
138template <MeasureLike M, NumericValue T>
139inline void to_json(::nlohmann::json& j, const MeasureRangeValue<M, T>& r) {
140 constexpr auto md = M::descriptor();
141 using unit_t = M::base_unit_t;
142 constexpr auto ud = unit_t::descriptor();
143 j = ::nlohmann::json{
144 {"m", md.id},
145 {"u", ud.id},
146 {"min", r.min().v},
147 {"max", r.max().v},
148 {"mi", r.inclusion().lower == Bound::Inclusive},
149 {"xi", r.inclusion().upper == Bound::Inclusive},
150 };
151}
152
153template <MeasureLike M, NumericValue T>
154inline void from_json(const ::nlohmann::json& j, MeasureRangeValue<M, T>& r) {
155 constexpr auto md = M::descriptor();
156 using unit_t = M::base_unit_t;
157 constexpr auto ud = unit_t::descriptor();
158 const auto mid = j.at("m").get<std::string>();
159 if (mid != md.id) {
160 throw ::nlohmann::detail::other_error::create(
161 502,
162 std::string{"dimval: measure mismatch: expected '"} + std::string{md.id} + "', got '" +
163 mid + "'",
164 &j);
165 }
166 if (const auto it = j.find("u"); it != j.end()) {
167 const auto uid = it->get<std::string>();
168 if (uid != ud.id) {
169 throw ::nlohmann::detail::other_error::create(
170 502,
171 std::string{"dimval: unit mismatch: expected '"} + std::string{ud.id} + "', got '" +
172 uid + "'",
173 &j);
174 }
175 }
176 const auto lo = j.at("min").get<T>();
177 const auto hi = j.at("max").get<T>();
178 RangeInclusion inc{
179 j.value("mi", true) ? Bound::Inclusive : Bound::Exclusive,
180 j.value("xi", true) ? Bound::Inclusive : Bound::Exclusive,
181 };
182 auto built = MeasureRangeValue<M, T>::make(MeasureValue<M, T>{lo}, MeasureValue<M, T>{hi}, inc);
183 if (!built) {
184 throw ::nlohmann::detail::other_error::create(
185 502, std::string{"dimval: invalid range: "} + built.error().message, &j);
186 }
187 r = *built;
188}
189
190inline void to_json(::nlohmann::json& j, const UnitDescriptor& d) {
191 j = ::nlohmann::json{
192 {"id", d.id},
193 {"symbol", d.symbol},
194 {"short_name", d.short_name},
195 {"long_name", d.long_name},
196 {"kind", d.kind},
197 {"factor", d.factor},
198 {"offset", d.offset},
199 {"formatter", d.formatter},
200 {"default_precision", d.default_precision},
201 };
202 // nlohmann does not serialize std::optional; an unset field emits null.
203 j["icon"] = d.icon ? ::nlohmann::json(*d.icon) : ::nlohmann::json(nullptr);
204 j["color"] = d.color ? ::nlohmann::json(*d.color) : ::nlohmann::json(nullptr);
205}
206
207inline void to_json(::nlohmann::json& j, const MeasureDescriptor& d) {
208 j = ::nlohmann::json{
209 {"id", d.id},
210 {"base_unit_id", d.base_unit_id},
211 {"name", d.name},
212 {"formatter", d.formatter},
213 {"default_precision", d.default_precision},
214 };
215 // nlohmann does not serialize std::optional; an unset field emits null.
216 j["icon"] = d.icon ? ::nlohmann::json(*d.icon) : ::nlohmann::json(nullptr);
217 j["color"] = d.color ? ::nlohmann::json(*d.color) : ::nlohmann::json(nullptr);
218}
219
220} // namespace dimval
221
222#endif // DIMVAL_WITH_NLOHMANN_JSON
MeasureValue<M,T>: a UnitValue tagged with an additional semantic measure.
UnitRangeValue and MeasureRangeValue — closed/open intervals of dimensional values.
Concepts and helper accessors that drive the static side of dimval.
UnitValue<U,T>: a strongly-typed value carrying a compile-time unit tag.