resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmJSONHelpers.h
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #pragma once
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <functional>
8 #include <map>
9 #include <string>
10 #include <vector>
11
12 #include <cm/optional>
13 #include <cm/string_view>
14
15 #include <cm3p/json/value.h>
16
17 template <typename T, typename E, typename... CallState>
18 using cmJSONHelper =
19   std::function<E(T& out, const Json::Value* value, CallState&&... state)>;
20
21 template <typename E, typename... CallState>
22 struct cmJSONHelperBuilder
23 {
24   template <typename T>
25   class Object
26   {
27   public:
28     Object(E&& success, E&& fail, bool allowExtra = true)
29       : Success(std::move(success))
30       , Fail(std::move(fail))
31       , AllowExtra(allowExtra)
32     {
33     }
34
35     template <typename U, typename M, typename F>
36     Object& Bind(const cm::string_view& name, M U::*member, F func,
37                  bool required = true)
38     {
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)...);
44                                },
45                                required);
46     }
47     template <typename M, typename F>
48     Object& Bind(const cm::string_view& name, std::nullptr_t, F func,
49                  bool required = true)
50     {
51       return this->BindPrivate(name,
52                                [func](T& /*out*/, const Json::Value* value,
53                                       CallState&&... state) -> E {
54                                  M dummy;
55                                  return func(dummy, value,
56                                              std::forward(state)...);
57                                },
58                                required);
59     }
60     template <typename F>
61     Object& Bind(const cm::string_view& name, F func, bool required = true)
62     {
63       return this->BindPrivate(name, MemberFunction(func), required);
64     }
65
66     E operator()(T& out, const Json::Value* value, CallState&&... state) const
67     {
68       if (!value && this->AnyRequired) {
69         return this->Fail;
70       }
71       if (value && !value->isObject()) {
72         return this->Fail;
73       }
74       Json::Value::Members extraFields;
75       if (value) {
76         extraFields = value->getMemberNames();
77       }
78
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) {
84             return result;
85           }
86           extraFields.erase(
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) {
91             return result;
92           }
93         } else {
94           return this->Fail;
95         }
96       }
97
98       return this->AllowExtra || extraFields.empty() ? this->Success
99                                                      : this->Fail;
100     }
101
102   private:
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)>;
106     struct Member
107     {
108       cm::string_view Name;
109       MemberFunction Function;
110       bool Required;
111     };
112     std::vector<Member> Members;
113     bool AnyRequired = false;
114     E Success;
115     E Fail;
116     bool AllowExtra;
117
118     Object& BindPrivate(const cm::string_view& name, MemberFunction&& func,
119                         bool required)
120     {
121       Member m;
122       m.Name = name;
123       m.Function = std::move(func);
124       m.Required = required;
125       this->Members.push_back(std::move(m));
126       if (required) {
127         this->AnyRequired = true;
128       }
129       return *this;
130     }
131   };
132   static cmJSONHelper<std::string, E, CallState...> String(
133     E success, E fail, const std::string& defval = "")
134   {
135     return [success, fail, defval](std::string& out, const Json::Value* value,
136                                    CallState&&... /*state*/) -> E {
137       if (!value) {
138         out = defval;
139         return success;
140       }
141       if (!value->isString()) {
142         return fail;
143       }
144       out = value->asString();
145       return success;
146     };
147   }
148
149   static cmJSONHelper<int, E, CallState...> Int(E success, E fail,
150                                                 int defval = 0)
151   {
152     return [success, fail, defval](int& out, const Json::Value* value,
153                                    CallState&&... /*state*/) -> E {
154       if (!value) {
155         out = defval;
156         return success;
157       }
158       if (!value->isInt()) {
159         return fail;
160       }
161       out = value->asInt();
162       return success;
163     };
164   }
165
166   static cmJSONHelper<unsigned int, E, CallState...> UInt(
167     E success, E fail, unsigned int defval = 0)
168   {
169     return [success, fail, defval](unsigned int& out, const Json::Value* value,
170                                    CallState&&... /*state*/) -> E {
171       if (!value) {
172         out = defval;
173         return success;
174       }
175       if (!value->isUInt()) {
176         return fail;
177       }
178       out = value->asUInt();
179       return success;
180     };
181   }
182
183   static cmJSONHelper<bool, E, CallState...> Bool(E success, E fail,
184                                                   bool defval = false)
185   {
186     return [success, fail, defval](bool& out, const Json::Value* value,
187                                    CallState&&... /*state*/) -> E {
188       if (!value) {
189         out = defval;
190         return success;
191       }
192       if (!value->isBool()) {
193         return fail;
194       }
195       out = value->asBool();
196       return success;
197     };
198   }
199
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)
203   {
204     return [success, fail, func, filter](std::vector<T>& out,
205                                          const Json::Value* value,
206                                          CallState&&... state) -> E {
207       if (!value) {
208         out.clear();
209         return success;
210       }
211       if (!value->isArray()) {
212         return fail;
213       }
214       out.clear();
215       for (auto const& item : *value) {
216         T t;
217         E result = func(t, &item, std::forward(state)...);
218         if (result != success) {
219           return result;
220         }
221         if (!filter(t)) {
222           continue;
223         }
224         out.push_back(std::move(t));
225       }
226       return success;
227     };
228   }
229
230   template <typename T, typename F>
231   static cmJSONHelper<std::vector<T>, E, CallState...> Vector(E success,
232                                                               E fail, F func)
233   {
234     return VectorFilter<T, F>(success, fail, func,
235                               [](const T&) { return true; });
236   }
237
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)
241   {
242     return [success, fail, func, filter](std::map<std::string, T>& out,
243                                          const Json::Value* value,
244                                          CallState&&... state) -> E {
245       if (!value) {
246         out.clear();
247         return success;
248       }
249       if (!value->isObject()) {
250         return fail;
251       }
252       out.clear();
253       for (auto const& key : value->getMemberNames()) {
254         if (!filter(key)) {
255           continue;
256         }
257         T t;
258         E result = func(t, &(*value)[key], std::forward(state)...);
259         if (result != success) {
260           return result;
261         }
262         out[key] = std::move(t);
263       }
264       return success;
265     };
266   }
267
268   template <typename T, typename F>
269   static cmJSONHelper<std::map<std::string, T>, E, CallState...> Map(E success,
270                                                                      E fail,
271                                                                      F func)
272   {
273     return MapFilter<T, F>(success, fail, func,
274                            [](const std::string&) { return true; });
275   }
276
277   template <typename T, typename F>
278   static cmJSONHelper<cm::optional<T>, E, CallState...> Optional(E success,
279                                                                  F func)
280   {
281     return [success, func](cm::optional<T>& out, const Json::Value* value,
282                            CallState&&... state) -> E {
283       if (!value) {
284         out.reset();
285         return success;
286       }
287       out.emplace();
288       return func(*out, value, std::forward(state)...);
289     };
290   }
291
292   template <typename T, typename F>
293   static cmJSONHelper<T, E, CallState...> Required(E fail, F func)
294   {
295     return [fail, func](T& out, const Json::Value* value,
296                         CallState&&... state) -> E {
297       if (!value) {
298         return fail;
299       }
300       return func(out, value, std::forward(state)...);
301     };
302   }
303 };