1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
12 #include <cm/optional>
13 #include <cm/string_view>
15 #include <cm3p/json/value.h>
17 template <typename T, typename E, typename... CallState>
19 std::function<E(T& out, const Json::Value* value, CallState&&... state)>;
21 template <typename E, typename... CallState>
22 struct cmJSONHelperBuilder
28 Object(E&& success, E&& fail, bool allowExtra = true)
29 : Success(std::move(success))
30 , Fail(std::move(fail))
31 , AllowExtra(allowExtra)
35 template <typename U, typename M, typename F>
36 Object& Bind(const cm::string_view& name, M U::*member, F func,
39 return this->BindPrivate(name,
40 [func, member](T& out, const Json::Value* value,
41 CallState&&... state) -> E {
42 return func(out.*member, value,
43 std::forward(state)...);
47 template <typename M, typename F>
48 Object& Bind(const cm::string_view& name, std::nullptr_t, F func,
51 return this->BindPrivate(name,
52 [func](T& /*out*/, const Json::Value* value,
53 CallState&&... state) -> E {
55 return func(dummy, value,
56 std::forward(state)...);
61 Object& Bind(const cm::string_view& name, F func, bool required = true)
63 return this->BindPrivate(name, MemberFunction(func), required);
66 E operator()(T& out, const Json::Value* value, CallState&&... state) const
68 if (!value && this->AnyRequired) {
71 if (value && !value->isObject()) {
74 Json::Value::Members extraFields;
76 extraFields = value->getMemberNames();
79 for (auto const& m : this->Members) {
80 std::string name(m.Name.data(), m.Name.size());
81 if (value && value->isMember(name)) {
82 E result = m.Function(out, &(*value)[name], std::forward(state)...);
83 if (result != this->Success) {
87 std::find(extraFields.begin(), extraFields.end(), name));
88 } else if (!m.Required) {
89 E result = m.Function(out, nullptr, std::forward(state)...);
90 if (result != this->Success) {
98 return this->AllowExtra || extraFields.empty() ? this->Success
103 // Not a true cmJSONHelper, it just happens to match the signature
104 using MemberFunction =
105 std::function<E(T& out, const Json::Value* value, CallState&&... state)>;
108 cm::string_view Name;
109 MemberFunction Function;
112 std::vector<Member> Members;
113 bool AnyRequired = false;
118 Object& BindPrivate(const cm::string_view& name, MemberFunction&& func,
123 m.Function = std::move(func);
124 m.Required = required;
125 this->Members.push_back(std::move(m));
127 this->AnyRequired = true;
132 static cmJSONHelper<std::string, E, CallState...> String(
133 E success, E fail, const std::string& defval = "")
135 return [success, fail, defval](std::string& out, const Json::Value* value,
136 CallState&&... /*state*/) -> E {
141 if (!value->isString()) {
144 out = value->asString();
149 static cmJSONHelper<int, E, CallState...> Int(E success, E fail,
152 return [success, fail, defval](int& out, const Json::Value* value,
153 CallState&&... /*state*/) -> E {
158 if (!value->isInt()) {
161 out = value->asInt();
166 static cmJSONHelper<unsigned int, E, CallState...> UInt(
167 E success, E fail, unsigned int defval = 0)
169 return [success, fail, defval](unsigned int& out, const Json::Value* value,
170 CallState&&... /*state*/) -> E {
175 if (!value->isUInt()) {
178 out = value->asUInt();
183 static cmJSONHelper<bool, E, CallState...> Bool(E success, E fail,
186 return [success, fail, defval](bool& out, const Json::Value* value,
187 CallState&&... /*state*/) -> E {
192 if (!value->isBool()) {
195 out = value->asBool();
200 template <typename T, typename F, typename Filter>
201 static cmJSONHelper<std::vector<T>, E, CallState...> VectorFilter(
202 E success, E fail, F func, Filter filter)
204 return [success, fail, func, filter](std::vector<T>& out,
205 const Json::Value* value,
206 CallState&&... state) -> E {
211 if (!value->isArray()) {
215 for (auto const& item : *value) {
217 E result = func(t, &item, std::forward(state)...);
218 if (result != success) {
224 out.push_back(std::move(t));
230 template <typename T, typename F>
231 static cmJSONHelper<std::vector<T>, E, CallState...> Vector(E success,
234 return VectorFilter<T, F>(success, fail, func,
235 [](const T&) { return true; });
238 template <typename T, typename F, typename Filter>
239 static cmJSONHelper<std::map<std::string, T>, E, CallState...> MapFilter(
240 E success, E fail, F func, Filter filter)
242 return [success, fail, func, filter](std::map<std::string, T>& out,
243 const Json::Value* value,
244 CallState&&... state) -> E {
249 if (!value->isObject()) {
253 for (auto const& key : value->getMemberNames()) {
258 E result = func(t, &(*value)[key], std::forward(state)...);
259 if (result != success) {
262 out[key] = std::move(t);
268 template <typename T, typename F>
269 static cmJSONHelper<std::map<std::string, T>, E, CallState...> Map(E success,
273 return MapFilter<T, F>(success, fail, func,
274 [](const std::string&) { return true; });
277 template <typename T, typename F>
278 static cmJSONHelper<cm::optional<T>, E, CallState...> Optional(E success,
281 return [success, func](cm::optional<T>& out, const Json::Value* value,
282 CallState&&... state) -> E {
288 return func(*out, value, std::forward(state)...);
292 template <typename T, typename F>
293 static cmJSONHelper<T, E, CallState...> Required(E fail, F func)
295 return [fail, func](T& out, const Json::Value* value,
296 CallState&&... state) -> E {
300 return func(out, value, std::forward(state)...);