| /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 |    file Copyright.txt or https://cmake.org/licensing for details.  */ | 
 | #pragma once | 
 |  | 
 | #include <algorithm> | 
 | #include <cstddef> | 
 | #include <functional> | 
 | #include <map> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include <cm/optional> | 
 | #include <cm/string_view> | 
 |  | 
 | #include <cm3p/json/value.h> | 
 |  | 
 | template <typename T, typename E> | 
 | using cmJSONHelper = std::function<E(T& out, const Json::Value* value)>; | 
 |  | 
 | template <typename T, typename E> | 
 | class cmJSONObjectHelper | 
 | { | 
 | public: | 
 |   cmJSONObjectHelper(E&& success, E&& fail, bool allowExtra = true); | 
 |  | 
 |   template <typename U, typename M, typename F> | 
 |   cmJSONObjectHelper& Bind(const cm::string_view& name, M U::*member, F func, | 
 |                            bool required = true); | 
 |   template <typename M, typename F> | 
 |   cmJSONObjectHelper& Bind(const cm::string_view& name, std::nullptr_t, F func, | 
 |                            bool required = true); | 
 |   template <typename F> | 
 |   cmJSONObjectHelper& Bind(const cm::string_view& name, F func, | 
 |                            bool required = true); | 
 |  | 
 |   E operator()(T& out, const Json::Value* value) const; | 
 |  | 
 | private: | 
 |   // Not a true cmJSONHelper, it just happens to match the signature | 
 |   using MemberFunction = std::function<E(T& out, const Json::Value* value)>; | 
 |   struct Member | 
 |   { | 
 |     cm::string_view Name; | 
 |     MemberFunction Function; | 
 |     bool Required; | 
 |   }; | 
 |   std::vector<Member> Members; | 
 |   bool AnyRequired = false; | 
 |   E Success; | 
 |   E Fail; | 
 |   bool AllowExtra; | 
 |  | 
 |   cmJSONObjectHelper& BindPrivate(const cm::string_view& name, | 
 |                                   MemberFunction&& func, bool required); | 
 | }; | 
 |  | 
 | template <typename T, typename E> | 
 | cmJSONObjectHelper<T, E>::cmJSONObjectHelper(E&& success, E&& fail, | 
 |                                              bool allowExtra) | 
 |   : Success(std::move(success)) | 
 |   , Fail(std::move(fail)) | 
 |   , AllowExtra(allowExtra) | 
 | { | 
 | } | 
 |  | 
 | template <typename T, typename E> | 
 | template <typename U, typename M, typename F> | 
 | cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind( | 
 |   const cm::string_view& name, M U::*member, F func, bool required) | 
 | { | 
 |   return this->BindPrivate( | 
 |     name, | 
 |     [func, member](T& out, const Json::Value* value) -> E { | 
 |       return func(out.*member, value); | 
 |     }, | 
 |     required); | 
 | } | 
 |  | 
 | template <typename T, typename E> | 
 | template <typename M, typename F> | 
 | cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind( | 
 |   const cm::string_view& name, std::nullptr_t, F func, bool required) | 
 | { | 
 |   return this->BindPrivate(name, | 
 |                            [func](T& /*out*/, const Json::Value* value) -> E { | 
 |                              M dummy; | 
 |                              return func(dummy, value); | 
 |                            }, | 
 |                            required); | 
 | } | 
 |  | 
 | template <typename T, typename E> | 
 | template <typename F> | 
 | cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind( | 
 |   const cm::string_view& name, F func, bool required) | 
 | { | 
 |   return this->BindPrivate(name, MemberFunction(func), required); | 
 | } | 
 |  | 
 | template <typename T, typename E> | 
 | cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::BindPrivate( | 
 |   const cm::string_view& name, MemberFunction&& func, bool required) | 
 | { | 
 |   Member m; | 
 |   m.Name = name; | 
 |   m.Function = std::move(func); | 
 |   m.Required = required; | 
 |   this->Members.push_back(std::move(m)); | 
 |   if (required) { | 
 |     this->AnyRequired = true; | 
 |   } | 
 |   return *this; | 
 | } | 
 |  | 
 | template <typename T, typename E> | 
 | E cmJSONObjectHelper<T, E>::operator()(T& out, const Json::Value* value) const | 
 | { | 
 |   if (!value && this->AnyRequired) { | 
 |     return this->Fail; | 
 |   } | 
 |   if (value && !value->isObject()) { | 
 |     return this->Fail; | 
 |   } | 
 |   Json::Value::Members extraFields; | 
 |   if (value) { | 
 |     extraFields = value->getMemberNames(); | 
 |   } | 
 |  | 
 |   for (auto const& m : this->Members) { | 
 |     std::string name(m.Name.data(), m.Name.size()); | 
 |     if (value && value->isMember(name)) { | 
 |       E result = m.Function(out, &(*value)[name]); | 
 |       if (result != this->Success) { | 
 |         return result; | 
 |       } | 
 |       extraFields.erase( | 
 |         std::find(extraFields.begin(), extraFields.end(), name)); | 
 |     } else if (!m.Required) { | 
 |       E result = m.Function(out, nullptr); | 
 |       if (result != this->Success) { | 
 |         return result; | 
 |       } | 
 |     } else { | 
 |       return this->Fail; | 
 |     } | 
 |   } | 
 |  | 
 |   return this->AllowExtra || extraFields.empty() ? this->Success : this->Fail; | 
 | } | 
 |  | 
 | template <typename E> | 
 | cmJSONHelper<std::string, E> cmJSONStringHelper(E success, E fail, | 
 |                                                 const std::string& defval = "") | 
 | { | 
 |   return | 
 |     [success, fail, defval](std::string& out, const Json::Value* value) -> E { | 
 |       if (!value) { | 
 |         out = defval; | 
 |         return success; | 
 |       } | 
 |       if (!value->isString()) { | 
 |         return fail; | 
 |       } | 
 |       out = value->asString(); | 
 |       return success; | 
 |     }; | 
 | } | 
 |  | 
 | template <typename E> | 
 | cmJSONHelper<int, E> cmJSONIntHelper(E success, E fail, int defval = 0) | 
 | { | 
 |   return [success, fail, defval](int& out, const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       out = defval; | 
 |       return success; | 
 |     } | 
 |     if (!value->isInt()) { | 
 |       return fail; | 
 |     } | 
 |     out = value->asInt(); | 
 |     return success; | 
 |   }; | 
 | } | 
 |  | 
 | template <typename E> | 
 | cmJSONHelper<unsigned int, E> cmJSONUIntHelper(E success, E fail, | 
 |                                                unsigned int defval = 0) | 
 | { | 
 |   return | 
 |     [success, fail, defval](unsigned int& out, const Json::Value* value) -> E { | 
 |       if (!value) { | 
 |         out = defval; | 
 |         return success; | 
 |       } | 
 |       if (!value->isUInt()) { | 
 |         return fail; | 
 |       } | 
 |       out = value->asUInt(); | 
 |       return success; | 
 |     }; | 
 | } | 
 |  | 
 | template <typename E> | 
 | cmJSONHelper<bool, E> cmJSONBoolHelper(E success, E fail, bool defval = false) | 
 | { | 
 |   return [success, fail, defval](bool& out, const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       out = defval; | 
 |       return success; | 
 |     } | 
 |     if (!value->isBool()) { | 
 |       return fail; | 
 |     } | 
 |     out = value->asBool(); | 
 |     return success; | 
 |   }; | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F, typename Filter> | 
 | cmJSONHelper<std::vector<T>, E> cmJSONVectorFilterHelper(E success, E fail, | 
 |                                                          F func, Filter filter) | 
 | { | 
 |   return [success, fail, func, filter](std::vector<T>& out, | 
 |                                        const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       out.clear(); | 
 |       return success; | 
 |     } | 
 |     if (!value->isArray()) { | 
 |       return fail; | 
 |     } | 
 |     out.clear(); | 
 |     for (auto const& item : *value) { | 
 |       T t; | 
 |       E result = func(t, &item); | 
 |       if (result != success) { | 
 |         return result; | 
 |       } | 
 |       if (!filter(t)) { | 
 |         continue; | 
 |       } | 
 |       out.push_back(std::move(t)); | 
 |     } | 
 |     return success; | 
 |   }; | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F> | 
 | cmJSONHelper<std::vector<T>, E> cmJSONVectorHelper(E success, E fail, F func) | 
 | { | 
 |   return cmJSONVectorFilterHelper<T, E, F>(success, fail, func, | 
 |                                            [](const T&) { return true; }); | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F, typename Filter> | 
 | cmJSONHelper<std::map<std::string, T>, E> cmJSONMapFilterHelper(E success, | 
 |                                                                 E fail, F func, | 
 |                                                                 Filter filter) | 
 | { | 
 |   return [success, fail, func, filter](std::map<std::string, T>& out, | 
 |                                        const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       out.clear(); | 
 |       return success; | 
 |     } | 
 |     if (!value->isObject()) { | 
 |       return fail; | 
 |     } | 
 |     out.clear(); | 
 |     for (auto const& key : value->getMemberNames()) { | 
 |       if (!filter(key)) { | 
 |         continue; | 
 |       } | 
 |       T t; | 
 |       E result = func(t, &(*value)[key]); | 
 |       if (result != success) { | 
 |         return result; | 
 |       } | 
 |       out[key] = std::move(t); | 
 |     } | 
 |     return success; | 
 |   }; | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F> | 
 | cmJSONHelper<std::map<std::string, T>, E> cmJSONMapHelper(E success, E fail, | 
 |                                                           F func) | 
 | { | 
 |   return cmJSONMapFilterHelper<T, E, F>( | 
 |     success, fail, func, [](const std::string&) { return true; }); | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F> | 
 | cmJSONHelper<cm::optional<T>, E> cmJSONOptionalHelper(E success, F func) | 
 | { | 
 |   return [success, func](cm::optional<T>& out, const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       out.reset(); | 
 |       return success; | 
 |     } | 
 |     out.emplace(); | 
 |     return func(*out, value); | 
 |   }; | 
 | } | 
 |  | 
 | template <typename T, typename E, typename F> | 
 | cmJSONHelper<T, E> cmJSONRequiredHelper(E fail, F func) | 
 | { | 
 |   return [fail, func](T& out, const Json::Value* value) -> E { | 
 |     if (!value) { | 
 |       return fail; | 
 |     } | 
 |     return func(out, value); | 
 |   }; | 
 | } |