|
|
@@ -17,143 +17,119 @@
|
|
|
template <typename T, typename E>
|
|
|
using cmJSONHelper = std::function<E(T& out, const Json::Value* value)>;
|
|
|
|
|
|
-template <typename T, typename E>
|
|
|
-class cmJSONObjectHelper
|
|
|
+template <typename E>
|
|
|
+struct cmJSONHelperBuilder
|
|
|
{
|
|
|
-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
|
|
|
+ template <typename T>
|
|
|
+ class Object
|
|
|
{
|
|
|
- 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)
|
|
|
-{
|
|
|
-}
|
|
|
+ public:
|
|
|
+ Object(E&& success, E&& fail, bool allowExtra = true)
|
|
|
+ : 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 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) -> E {
|
|
|
+ return func(out.*member, value);
|
|
|
+ },
|
|
|
+ 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) -> E {
|
|
|
+ M dummy;
|
|
|
+ return func(dummy, value);
|
|
|
+ },
|
|
|
+ required);
|
|
|
+ }
|
|
|
+ template <typename F>
|
|
|
+ Object& Bind(const cm::string_view& name, F func, bool required = true)
|
|
|
+ {
|
|
|
+ return this->BindPrivate(name, MemberFunction(func), 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);
|
|
|
-}
|
|
|
+ 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();
|
|
|
+ }
|
|
|
|
|
|
-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);
|
|
|
-}
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-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;
|
|
|
-}
|
|
|
+ return this->AllowExtra || extraFields.empty() ? this->Success
|
|
|
+ : this->Fail;
|
|
|
+ }
|
|
|
|
|
|
-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();
|
|
|
- }
|
|
|
+ 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;
|
|
|
|
|
|
- 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;
|
|
|
+ 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;
|
|
|
}
|
|
|
- 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;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- 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 {
|
|
|
+ };
|
|
|
+ static cmJSONHelper<std::string, E> String(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;
|
|
|
@@ -164,30 +140,28 @@ cmJSONHelper<std::string, E> cmJSONStringHelper(E success, E 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;
|
|
|
+ static cmJSONHelper<int, E> Int(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;
|
|
|
- }
|
|
|
- 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 {
|
|
|
+ static cmJSONHelper<unsigned int, E> UInt(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;
|
|
|
@@ -198,118 +172,119 @@ cmJSONHelper<unsigned int, E> cmJSONUIntHelper(E success, E 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;
|
|
|
+ static cmJSONHelper<bool, E> Bool(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;
|
|
|
- }
|
|
|
- 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;
|
|
|
+ template <typename T, typename F, typename Filter>
|
|
|
+ static cmJSONHelper<std::vector<T>, E> VectorFilter(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 (!filter(t)) {
|
|
|
- continue;
|
|
|
+ if (!value->isArray()) {
|
|
|
+ return fail;
|
|
|
}
|
|
|
- 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();
|
|
|
+ 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;
|
|
|
- }
|
|
|
- if (!value->isObject()) {
|
|
|
- return fail;
|
|
|
- }
|
|
|
- out.clear();
|
|
|
- for (auto const& key : value->getMemberNames()) {
|
|
|
- if (!filter(key)) {
|
|
|
- continue;
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T, typename F>
|
|
|
+ static cmJSONHelper<std::vector<T>, E> Vector(E success, E fail, F func)
|
|
|
+ {
|
|
|
+ return VectorFilter<T, F>(success, fail, func,
|
|
|
+ [](const T&) { return true; });
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T, typename F, typename Filter>
|
|
|
+ static cmJSONHelper<std::map<std::string, T>, E> MapFilter(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;
|
|
|
}
|
|
|
- T t;
|
|
|
- E result = func(t, &(*value)[key]);
|
|
|
- if (result != success) {
|
|
|
- return result;
|
|
|
+ if (!value->isObject()) {
|
|
|
+ return fail;
|
|
|
}
|
|
|
- out[key] = std::move(t);
|
|
|
- }
|
|
|
- return success;
|
|
|
- };
|
|
|
-}
|
|
|
+ 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 F>
|
|
|
+ static cmJSONHelper<std::map<std::string, T>, E> Map(E success, E fail,
|
|
|
+ F func)
|
|
|
+ {
|
|
|
+ return MapFilter<T, 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 F>
|
|
|
+ static cmJSONHelper<cm::optional<T>, E> Optional(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);
|
|
|
- };
|
|
|
-}
|
|
|
+ template <typename T, typename F>
|
|
|
+ static cmJSONHelper<T, E> Required(E fail, F func)
|
|
|
+ {
|
|
|
+ return [fail, func](T& out, const Json::Value* value) -> E {
|
|
|
+ if (!value) {
|
|
|
+ return fail;
|
|
|
+ }
|
|
|
+ return func(out, value);
|
|
|
+ };
|
|
|
+ }
|
|
|
+};
|