| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 | 
							- /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 
-    file Copyright.txt or https://cmake.org/licensing for details.  */
 
- #pragma once
 
- #include "cmConfigure.h" // IWYU pragma: keep
 
- #include <algorithm>
 
- #include <functional>
 
- #include <iostream>
 
- #include <map>
 
- #include <string>
 
- #include <utility>
 
- #include <vector>
 
- #include <cm/optional>
 
- #include <cm/string_view>
 
- #include <cm3p/json/value.h>
 
- #include "cmJSONState.h"
 
- #include "cmStringAlgorithms.h"
 
- template <typename T>
 
- using cmJSONHelper =
 
-   std::function<bool(T& out, const Json::Value* value, cmJSONState* state)>;
 
- using ErrorGenerator = std::function<void(const Json::Value*, cmJSONState*)>;
 
- namespace JsonErrors {
 
- enum ObjectError
 
- {
 
-   RequiredMissing,
 
-   InvalidObject,
 
-   ExtraField,
 
-   MissingRequired
 
- };
 
- using ErrorGenerator = std::function<void(const Json::Value*, cmJSONState*)>;
 
- using ObjectErrorGenerator =
 
-   std::function<ErrorGenerator(ObjectError, const Json::Value::Members&)>;
 
- ErrorGenerator EXPECTED_TYPE(const std::string& type);
 
- void INVALID_STRING(const Json::Value* value, cmJSONState* state);
 
- void INVALID_BOOL(const Json::Value* value, cmJSONState* state);
 
- void INVALID_INT(const Json::Value* value, cmJSONState* state);
 
- void INVALID_UINT(const Json::Value* value, cmJSONState* state);
 
- ObjectErrorGenerator INVALID_NAMED_OBJECT(
 
-   const std::function<std::string(const Json::Value*, cmJSONState*)>&
 
-     nameGenerator);
 
- ErrorGenerator INVALID_OBJECT(ObjectError errorType,
 
-                               const Json::Value::Members& extraFields);
 
- ErrorGenerator INVALID_NAMED_OBJECT_KEY(
 
-   ObjectError errorType, const Json::Value::Members& extraFields);
 
- }
 
- struct cmJSONHelperBuilder
 
- {
 
-   template <typename T>
 
-   class Object
 
-   {
 
-   public:
 
-     Object(JsonErrors::ObjectErrorGenerator error = JsonErrors::INVALID_OBJECT,
 
-            bool allowExtra = true)
 
-       : Error(std::move(error))
 
-       , AllowExtra(allowExtra)
 
-     {
 
-     }
 
-     template <typename U, typename M, typename F>
 
-     Object& Bind(const cm::string_view& name, M U::*member, F func,
 
-                  bool required = true)
 
-     {
 
-       return this->BindPrivate(
 
-         name,
 
-         [func, member](T& out, const Json::Value* value, cmJSONState* state)
 
-           -> bool { return func(out.*member, value, state); },
 
-         required);
 
-     }
 
-     template <typename M, typename F>
 
-     Object& Bind(const cm::string_view& name, std::nullptr_t, F func,
 
-                  bool required = true)
 
-     {
 
-       return this->BindPrivate(
 
-         name,
 
-         [func](T& /*out*/, const Json::Value* value,
 
-                cmJSONState* state) -> bool {
 
-           M dummy;
 
-           return func(dummy, value, state);
 
-         },
 
-         required);
 
-     }
 
-     template <typename F>
 
-     Object& Bind(const cm::string_view& name, F func, bool required = true)
 
-     {
 
-       return this->BindPrivate(name, MemberFunction(func), required);
 
-     }
 
-     bool operator()(T& out, const Json::Value* value, cmJSONState* state) const
 
-     {
 
-       Json::Value::Members extraFields;
 
-       bool success = true;
 
-       if (!value && this->AnyRequired) {
 
-         Error(JsonErrors::ObjectError::RequiredMissing, extraFields)(value,
 
-                                                                      state);
 
-         return false;
 
-       }
 
-       if (value && !value->isObject()) {
 
-         Error(JsonErrors::ObjectError::InvalidObject, extraFields)(value,
 
-                                                                    state);
 
-         return false;
 
-       }
 
-       if (value) {
 
-         extraFields = value->getMemberNames();
 
-       }
 
-       if (state->allowComments) {
 
-         extraFields.erase(
 
-           std::remove(extraFields.begin(), extraFields.end(), "$comment"),
 
-           extraFields.end());
 
-       }
 
-       for (auto const& m : this->Members) {
 
-         std::string name(m.Name.data(), m.Name.size());
 
-         state->push_stack(name, value);
 
-         if (value && value->isMember(name)) {
 
-           if (!m.Function(out, &(*value)[name], state)) {
 
-             success = false;
 
-           }
 
-           extraFields.erase(
 
-             std::find(extraFields.begin(), extraFields.end(), name));
 
-         } else if (!m.Required) {
 
-           if (!m.Function(out, nullptr, state)) {
 
-             success = false;
 
-           }
 
-         } else {
 
-           Error(JsonErrors::ObjectError::MissingRequired, extraFields)(value,
 
-                                                                        state);
 
-           success = false;
 
-         }
 
-         state->pop_stack();
 
-       }
 
-       if (!this->AllowExtra && !extraFields.empty()) {
 
-         Error(JsonErrors::ObjectError::ExtraField, extraFields)(value, state);
 
-         success = false;
 
-       }
 
-       return success;
 
-     }
 
-   private:
 
-     // Not a true cmJSONHelper, it just happens to match the signature
 
-     using MemberFunction = std::function<bool(T& out, const Json::Value* value,
 
-                                               cmJSONState* state)>;
 
-     struct Member
 
-     {
 
-       cm::string_view Name;
 
-       MemberFunction Function;
 
-       bool Required;
 
-     };
 
-     std::vector<Member> Members;
 
-     bool AnyRequired = false;
 
-     JsonErrors::ObjectErrorGenerator Error;
 
-     bool AllowExtra;
 
-     Object& 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;
 
-     }
 
-   };
 
-   static cmJSONHelper<std::string> String(
 
-     const JsonErrors::ErrorGenerator& error = JsonErrors::INVALID_STRING,
 
-     const std::string& defval = "")
 
-   {
 
-     return [error, defval](std::string& out, const Json::Value* value,
 
-                            cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         out = defval;
 
-         return true;
 
-       }
 
-       if (!value->isString()) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       out = value->asString();
 
-       return true;
 
-     };
 
-   };
 
-   static cmJSONHelper<std::string> String(const std::string& defval)
 
-   {
 
-     return String(JsonErrors::INVALID_STRING, defval);
 
-   };
 
-   static cmJSONHelper<int> Int(
 
-     const JsonErrors::ErrorGenerator& error = JsonErrors::INVALID_INT,
 
-     int defval = 0)
 
-   {
 
-     return [error, defval](int& out, const Json::Value* value,
 
-                            cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         out = defval;
 
-         return true;
 
-       }
 
-       if (!value->isInt()) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       out = value->asInt();
 
-       return true;
 
-     };
 
-   }
 
-   static cmJSONHelper<int> Int(int defval)
 
-   {
 
-     return Int(JsonErrors::INVALID_INT, defval);
 
-   };
 
-   static cmJSONHelper<unsigned int> UInt(
 
-     const JsonErrors::ErrorGenerator& error = JsonErrors::INVALID_UINT,
 
-     unsigned int defval = 0)
 
-   {
 
-     return [error, defval](unsigned int& out, const Json::Value* value,
 
-                            cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         out = defval;
 
-         return true;
 
-       }
 
-       if (!value->isUInt()) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       out = value->asUInt();
 
-       return true;
 
-     };
 
-   }
 
-   static cmJSONHelper<unsigned int> UInt(unsigned int defval)
 
-   {
 
-     return UInt(JsonErrors::INVALID_UINT, defval);
 
-   }
 
-   static cmJSONHelper<bool> Bool(
 
-     const JsonErrors::ErrorGenerator& error = JsonErrors::INVALID_BOOL,
 
-     bool defval = false)
 
-   {
 
-     return [error, defval](bool& out, const Json::Value* value,
 
-                            cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         out = defval;
 
-         return true;
 
-       }
 
-       if (!value->isBool()) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       out = value->asBool();
 
-       return true;
 
-     };
 
-   }
 
-   static cmJSONHelper<bool> Bool(bool defval)
 
-   {
 
-     return Bool(JsonErrors::INVALID_BOOL, defval);
 
-   }
 
-   template <typename T, typename F, typename Filter>
 
-   static cmJSONHelper<std::vector<T>> VectorFilter(
 
-     const JsonErrors::ErrorGenerator& error, F func, Filter filter)
 
-   {
 
-     return [error, func, filter](std::vector<T>& out, const Json::Value* value,
 
-                                  cmJSONState* state) -> bool {
 
-       bool success = true;
 
-       if (!value) {
 
-         out.clear();
 
-         return true;
 
-       }
 
-       if (!value->isArray()) {
 
-         error(value, state);
 
-         return false;
 
-       }
 
-       out.clear();
 
-       int index = 0;
 
-       for (auto const& item : *value) {
 
-         state->push_stack(cmStrCat("$vector_item_", index++), &item);
 
-         T t;
 
-         if (!func(t, &item, state)) {
 
-           success = false;
 
-         }
 
-         if (!filter(t)) {
 
-           state->pop_stack();
 
-           continue;
 
-         }
 
-         out.push_back(std::move(t));
 
-         state->pop_stack();
 
-       }
 
-       return success;
 
-     };
 
-   }
 
-   template <typename T, typename F>
 
-   static cmJSONHelper<std::vector<T>> Vector(JsonErrors::ErrorGenerator error,
 
-                                              F func)
 
-   {
 
-     return VectorFilter<T, F>(std::move(error), func,
 
-                               [](const T&) { return true; });
 
-   }
 
-   template <typename T, typename F, typename Filter>
 
-   static cmJSONHelper<std::map<std::string, T>> MapFilter(
 
-     const JsonErrors::ErrorGenerator& error, F func, Filter filter)
 
-   {
 
-     return [error, func, filter](std::map<std::string, T>& out,
 
-                                  const Json::Value* value,
 
-                                  cmJSONState* state) -> bool {
 
-       bool success = true;
 
-       if (!value) {
 
-         out.clear();
 
-         return true;
 
-       }
 
-       if (!value->isObject()) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       out.clear();
 
-       for (auto const& key : value->getMemberNames()) {
 
-         state->push_stack(cmStrCat(key, ""), &(*value)[key]);
 
-         if (!filter(key)) {
 
-           state->pop_stack();
 
-           continue;
 
-         }
 
-         T t;
 
-         if (!func(t, &(*value)[key], state)) {
 
-           success = false;
 
-         }
 
-         out[key] = std::move(t);
 
-         state->pop_stack();
 
-       }
 
-       return success;
 
-     };
 
-   }
 
-   template <typename T, typename F>
 
-   static cmJSONHelper<std::map<std::string, T>> Map(
 
-     const JsonErrors::ErrorGenerator& error, F func)
 
-   {
 
-     return MapFilter<T, F>(error, func,
 
-                            [](const std::string&) { return true; });
 
-   }
 
-   template <typename T, typename F>
 
-   static cmJSONHelper<cm::optional<T>> Optional(F func)
 
-   {
 
-     return [func](cm::optional<T>& out, const Json::Value* value,
 
-                   cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         out.reset();
 
-         return true;
 
-       }
 
-       out.emplace();
 
-       return func(*out, value, state);
 
-     };
 
-   }
 
-   template <typename T, typename F>
 
-   static cmJSONHelper<T> Required(const JsonErrors::ErrorGenerator& error,
 
-                                   F func)
 
-   {
 
-     return [error, func](T& out, const Json::Value* value,
 
-                          cmJSONState* state) -> bool {
 
-       if (!value) {
 
-         error(value, state);
 
-         ;
 
-         return false;
 
-       }
 
-       return func(out, value, state);
 
-     };
 
-   }
 
- };
 
 
  |