]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef CEPH_JSON_H |
2 | #define CEPH_JSON_H | |
3 | ||
9f95a23c TL |
4 | #include <stdexcept> |
5 | #include <typeindex> | |
7c673cae | 6 | #include <include/types.h> |
9f95a23c | 7 | #include <boost/container/flat_map.hpp> |
f67539c2 TL |
8 | #include <boost/container/flat_set.hpp> |
9 | #include <include/ceph_fs.h> | |
10 | #include "common/ceph_time.h" | |
7c673cae FG |
11 | |
12 | #include "json_spirit/json_spirit.h" | |
7c673cae FG |
13 | |
14 | #include "Formatter.h" | |
15 | ||
7c673cae FG |
16 | |
17 | ||
18 | class JSONObj; | |
19 | ||
20 | class JSONObjIter { | |
9f95a23c | 21 | typedef std::map<std::string, JSONObj *>::iterator map_iter_t; |
7c673cae FG |
22 | map_iter_t cur; |
23 | map_iter_t last; | |
24 | ||
25 | public: | |
26 | JSONObjIter(); | |
27 | ~JSONObjIter(); | |
28 | void set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_end); | |
29 | ||
30 | void operator++(); | |
31 | JSONObj *operator*(); | |
32 | ||
33 | bool end() const { | |
34 | return (cur == last); | |
35 | } | |
36 | }; | |
37 | ||
38 | class JSONObj | |
39 | { | |
40 | JSONObj *parent; | |
11fdf7f2 TL |
41 | public: |
42 | struct data_val { | |
9f95a23c | 43 | std::string str; |
11fdf7f2 TL |
44 | bool quoted{false}; |
45 | ||
46 | void set(std::string_view s, bool q) { | |
47 | str = s; | |
48 | quoted = q; | |
49 | } | |
50 | }; | |
7c673cae | 51 | protected: |
9f95a23c TL |
52 | std::string name; // corresponds to obj_type in XMLObj |
53 | json_spirit::Value data; | |
11fdf7f2 TL |
54 | struct data_val val; |
55 | bool data_quoted{false}; | |
9f95a23c TL |
56 | std::multimap<std::string, JSONObj *> children; |
57 | std::map<std::string, data_val> attr_map; | |
58 | void handle_value(json_spirit::Value v); | |
7c673cae FG |
59 | |
60 | public: | |
61 | ||
62 | JSONObj() : parent(NULL){} | |
63 | ||
64 | virtual ~JSONObj(); | |
65 | ||
9f95a23c | 66 | void init(JSONObj *p, json_spirit::Value v, std::string n); |
7c673cae | 67 | |
9f95a23c | 68 | std::string& get_name() { return name; } |
11fdf7f2 | 69 | data_val& get_data_val() { return val; } |
9f95a23c TL |
70 | const std::string& get_data() { return val.str; } |
71 | bool get_data(const std::string& key, data_val *dest); | |
7c673cae | 72 | JSONObj *get_parent(); |
9f95a23c TL |
73 | void add_child(std::string el, JSONObj *child); |
74 | bool get_attr(std::string name, data_val& attr); | |
75 | JSONObjIter find(const std::string& name); | |
7c673cae | 76 | JSONObjIter find_first(); |
9f95a23c TL |
77 | JSONObjIter find_first(const std::string& name); |
78 | JSONObj *find_obj(const std::string& name); | |
7c673cae | 79 | |
9f95a23c TL |
80 | friend std::ostream& operator<<(std::ostream &out, |
81 | const JSONObj &obj); // does not work, FIXME | |
7c673cae FG |
82 | |
83 | bool is_array(); | |
84 | bool is_object(); | |
9f95a23c | 85 | std::vector<std::string> get_array_elements(); |
7c673cae FG |
86 | }; |
87 | ||
9f95a23c | 88 | inline std::ostream& operator<<(std::ostream &out, const JSONObj::data_val& dv) { |
11fdf7f2 TL |
89 | const char *q = (dv.quoted ? "\"" : ""); |
90 | out << q << dv.str << q; | |
91 | return out; | |
92 | } | |
93 | ||
7c673cae FG |
94 | class JSONParser : public JSONObj |
95 | { | |
96 | int buf_len; | |
9f95a23c | 97 | std::string json_buffer; |
7c673cae FG |
98 | bool success; |
99 | public: | |
100 | JSONParser(); | |
101 | ~JSONParser() override; | |
102 | void handle_data(const char *s, int len); | |
103 | ||
104 | bool parse(const char *buf_, int len); | |
105 | bool parse(int len); | |
106 | bool parse(); | |
107 | bool parse(const char *file_name); | |
108 | ||
109 | const char *get_json() { return json_buffer.c_str(); } | |
110 | void set_failure() { success = false; } | |
111 | }; | |
112 | ||
9f95a23c | 113 | void encode_json(const char *name, const JSONObj::data_val& v, ceph::Formatter *f); |
7c673cae FG |
114 | |
115 | class JSONDecoder { | |
116 | public: | |
9f95a23c TL |
117 | struct err : std::runtime_error { |
118 | using runtime_error::runtime_error; | |
7c673cae FG |
119 | }; |
120 | ||
121 | JSONParser parser; | |
122 | ||
9f95a23c | 123 | JSONDecoder(ceph::buffer::list& bl) { |
7c673cae | 124 | if (!parser.parse(bl.c_str(), bl.length())) { |
9f95a23c | 125 | std::cout << "JSONDecoder::err()" << std::endl; |
7c673cae FG |
126 | throw JSONDecoder::err("failed to parse JSON input"); |
127 | } | |
128 | } | |
129 | ||
130 | template<class T> | |
131 | static bool decode_json(const char *name, T& val, JSONObj *obj, bool mandatory = false); | |
132 | ||
133 | template<class C> | |
134 | static bool decode_json(const char *name, C& container, void (*cb)(C&, JSONObj *obj), JSONObj *obj, bool mandatory = false); | |
135 | ||
136 | template<class T> | |
b32b8144 | 137 | static void decode_json(const char *name, T& val, const T& default_val, JSONObj *obj); |
11fdf7f2 TL |
138 | |
139 | template<class T> | |
140 | static bool decode_json(const char *name, boost::optional<T>& val, JSONObj *obj, bool mandatory = false); | |
141 | ||
9f95a23c TL |
142 | template<class T> |
143 | static bool decode_json(const char *name, std::optional<T>& val, JSONObj *obj, bool mandatory = false); | |
144 | ||
7c673cae FG |
145 | }; |
146 | ||
147 | template<class T> | |
148 | void decode_json_obj(T& val, JSONObj *obj) | |
149 | { | |
150 | val.decode_json(obj); | |
151 | } | |
152 | ||
9f95a23c | 153 | inline void decode_json_obj(std::string& val, JSONObj *obj) |
7c673cae FG |
154 | { |
155 | val = obj->get_data(); | |
156 | } | |
157 | ||
11fdf7f2 TL |
158 | static inline void decode_json_obj(JSONObj::data_val& val, JSONObj *obj) |
159 | { | |
160 | val = obj->get_data_val(); | |
161 | } | |
162 | ||
7c673cae FG |
163 | void decode_json_obj(unsigned long long& val, JSONObj *obj); |
164 | void decode_json_obj(long long& val, JSONObj *obj); | |
165 | void decode_json_obj(unsigned long& val, JSONObj *obj); | |
166 | void decode_json_obj(long& val, JSONObj *obj); | |
167 | void decode_json_obj(unsigned& val, JSONObj *obj); | |
168 | void decode_json_obj(int& val, JSONObj *obj); | |
169 | void decode_json_obj(bool& val, JSONObj *obj); | |
9f95a23c | 170 | void decode_json_obj(ceph::buffer::list& val, JSONObj *obj); |
7c673cae FG |
171 | class utime_t; |
172 | void decode_json_obj(utime_t& val, JSONObj *obj); | |
f67539c2 TL |
173 | void decode_json_obj(ceph_dir_layout& i, JSONObj *obj); |
174 | ||
175 | void decode_json_obj(ceph::real_time& val, JSONObj *obj); | |
176 | void decode_json_obj(ceph::coarse_real_time& val, JSONObj *obj); | |
7c673cae FG |
177 | |
178 | template<class T> | |
9f95a23c | 179 | void decode_json_obj(std::list<T>& l, JSONObj *obj) |
7c673cae FG |
180 | { |
181 | l.clear(); | |
182 | ||
183 | JSONObjIter iter = obj->find_first(); | |
184 | ||
185 | for (; !iter.end(); ++iter) { | |
186 | T val; | |
187 | JSONObj *o = *iter; | |
188 | decode_json_obj(val, o); | |
189 | l.push_back(val); | |
190 | } | |
191 | } | |
192 | ||
193 | template<class T> | |
9f95a23c | 194 | void decode_json_obj(std::deque<T>& l, JSONObj *obj) |
7c673cae FG |
195 | { |
196 | l.clear(); | |
197 | ||
198 | JSONObjIter iter = obj->find_first(); | |
199 | ||
200 | for (; !iter.end(); ++iter) { | |
201 | T val; | |
202 | JSONObj *o = *iter; | |
203 | decode_json_obj(val, o); | |
204 | l.push_back(val); | |
205 | } | |
206 | } | |
207 | ||
208 | template<class T> | |
9f95a23c | 209 | void decode_json_obj(std::set<T>& l, JSONObj *obj) |
7c673cae FG |
210 | { |
211 | l.clear(); | |
212 | ||
213 | JSONObjIter iter = obj->find_first(); | |
214 | ||
215 | for (; !iter.end(); ++iter) { | |
216 | T val; | |
217 | JSONObj *o = *iter; | |
218 | decode_json_obj(val, o); | |
219 | l.insert(val); | |
220 | } | |
221 | } | |
222 | ||
1e59de90 TL |
223 | template<class T, class Compare, class Alloc> |
224 | void decode_json_obj(boost::container::flat_set<T, Compare, Alloc>& l, JSONObj *obj) | |
f67539c2 TL |
225 | { |
226 | l.clear(); | |
227 | ||
228 | JSONObjIter iter = obj->find_first(); | |
229 | ||
230 | for (; !iter.end(); ++iter) { | |
231 | T val; | |
232 | JSONObj *o = *iter; | |
233 | decode_json_obj(val, o); | |
234 | l.insert(val); | |
235 | } | |
236 | } | |
237 | ||
7c673cae | 238 | template<class T> |
9f95a23c | 239 | void decode_json_obj(std::vector<T>& l, JSONObj *obj) |
7c673cae FG |
240 | { |
241 | l.clear(); | |
242 | ||
243 | JSONObjIter iter = obj->find_first(); | |
244 | ||
245 | for (; !iter.end(); ++iter) { | |
246 | T val; | |
247 | JSONObj *o = *iter; | |
248 | decode_json_obj(val, o); | |
249 | l.push_back(val); | |
250 | } | |
251 | } | |
252 | ||
31f18b77 | 253 | template<class K, class V, class C = std::less<K> > |
9f95a23c | 254 | void decode_json_obj(std::map<K, V, C>& m, JSONObj *obj) |
7c673cae FG |
255 | { |
256 | m.clear(); | |
257 | ||
258 | JSONObjIter iter = obj->find_first(); | |
259 | ||
260 | for (; !iter.end(); ++iter) { | |
261 | K key; | |
262 | V val; | |
263 | JSONObj *o = *iter; | |
264 | JSONDecoder::decode_json("key", key, o); | |
265 | JSONDecoder::decode_json("val", val, o); | |
266 | m[key] = val; | |
267 | } | |
268 | } | |
269 | ||
f67539c2 TL |
270 | template<class K, class V, class C = std::less<K> > |
271 | void decode_json_obj(boost::container::flat_map<K, V, C>& m, JSONObj *obj) | |
272 | { | |
273 | m.clear(); | |
274 | ||
275 | JSONObjIter iter = obj->find_first(); | |
276 | ||
277 | for (; !iter.end(); ++iter) { | |
278 | K key; | |
279 | V val; | |
280 | JSONObj *o = *iter; | |
281 | JSONDecoder::decode_json("key", key, o); | |
282 | JSONDecoder::decode_json("val", val, o); | |
283 | m[key] = val; | |
284 | } | |
285 | } | |
286 | ||
7c673cae | 287 | template<class K, class V> |
9f95a23c | 288 | void decode_json_obj(std::multimap<K, V>& m, JSONObj *obj) |
7c673cae FG |
289 | { |
290 | m.clear(); | |
291 | ||
292 | JSONObjIter iter = obj->find_first(); | |
293 | ||
294 | for (; !iter.end(); ++iter) { | |
295 | K key; | |
296 | V val; | |
297 | JSONObj *o = *iter; | |
298 | JSONDecoder::decode_json("key", key, o); | |
299 | JSONDecoder::decode_json("val", val, o); | |
300 | m.insert(make_pair(key, val)); | |
301 | } | |
302 | } | |
303 | ||
9f95a23c TL |
304 | template<class K, class V> |
305 | void decode_json_obj(boost::container::flat_map<K, V>& m, JSONObj *obj) | |
306 | { | |
307 | m.clear(); | |
308 | ||
309 | JSONObjIter iter = obj->find_first(); | |
310 | ||
311 | for (; !iter.end(); ++iter) { | |
312 | K key; | |
313 | V val; | |
314 | JSONObj *o = *iter; | |
315 | JSONDecoder::decode_json("key", key, o); | |
316 | JSONDecoder::decode_json("val", val, o); | |
317 | m[key] = val; | |
318 | } | |
319 | } | |
7c673cae FG |
320 | template<class C> |
321 | void decode_json_obj(C& container, void (*cb)(C&, JSONObj *obj), JSONObj *obj) | |
322 | { | |
323 | container.clear(); | |
324 | ||
325 | JSONObjIter iter = obj->find_first(); | |
326 | ||
327 | for (; !iter.end(); ++iter) { | |
328 | JSONObj *o = *iter; | |
329 | cb(container, o); | |
330 | } | |
331 | } | |
332 | ||
333 | template<class T> | |
334 | bool JSONDecoder::decode_json(const char *name, T& val, JSONObj *obj, bool mandatory) | |
335 | { | |
336 | JSONObjIter iter = obj->find_first(name); | |
337 | if (iter.end()) { | |
338 | if (mandatory) { | |
9f95a23c | 339 | std::string s = "missing mandatory field " + std::string(name); |
7c673cae FG |
340 | throw err(s); |
341 | } | |
1e59de90 TL |
342 | if constexpr (std::is_default_constructible_v<T>) { |
343 | val = T(); | |
344 | } | |
7c673cae FG |
345 | return false; |
346 | } | |
347 | ||
348 | try { | |
349 | decode_json_obj(val, *iter); | |
9f95a23c TL |
350 | } catch (const err& e) { |
351 | std::string s = std::string(name) + ": "; | |
352 | s.append(e.what()); | |
7c673cae FG |
353 | throw err(s); |
354 | } | |
355 | ||
356 | return true; | |
357 | } | |
358 | ||
359 | template<class C> | |
360 | bool JSONDecoder::decode_json(const char *name, C& container, void (*cb)(C&, JSONObj *), JSONObj *obj, bool mandatory) | |
361 | { | |
362 | container.clear(); | |
363 | ||
364 | JSONObjIter iter = obj->find_first(name); | |
365 | if (iter.end()) { | |
366 | if (mandatory) { | |
9f95a23c | 367 | std::string s = "missing mandatory field " + std::string(name); |
7c673cae FG |
368 | throw err(s); |
369 | } | |
370 | return false; | |
371 | } | |
372 | ||
373 | try { | |
374 | decode_json_obj(container, cb, *iter); | |
9f95a23c TL |
375 | } catch (const err& e) { |
376 | std::string s = std::string(name) + ": "; | |
377 | s.append(e.what()); | |
7c673cae FG |
378 | throw err(s); |
379 | } | |
380 | ||
381 | return true; | |
382 | } | |
383 | ||
384 | template<class T> | |
b32b8144 | 385 | void JSONDecoder::decode_json(const char *name, T& val, const T& default_val, JSONObj *obj) |
7c673cae FG |
386 | { |
387 | JSONObjIter iter = obj->find_first(name); | |
388 | if (iter.end()) { | |
389 | val = default_val; | |
390 | return; | |
391 | } | |
392 | ||
393 | try { | |
394 | decode_json_obj(val, *iter); | |
9f95a23c | 395 | } catch (const err& e) { |
7c673cae | 396 | val = default_val; |
9f95a23c TL |
397 | std::string s = std::string(name) + ": "; |
398 | s.append(e.what()); | |
7c673cae FG |
399 | throw err(s); |
400 | } | |
401 | } | |
402 | ||
11fdf7f2 TL |
403 | template<class T> |
404 | bool JSONDecoder::decode_json(const char *name, boost::optional<T>& val, JSONObj *obj, bool mandatory) | |
405 | { | |
406 | JSONObjIter iter = obj->find_first(name); | |
407 | if (iter.end()) { | |
408 | if (mandatory) { | |
9f95a23c | 409 | std::string s = "missing mandatory field " + std::string(name); |
11fdf7f2 TL |
410 | throw err(s); |
411 | } | |
412 | val = boost::none; | |
413 | return false; | |
414 | } | |
415 | ||
416 | try { | |
417 | val.reset(T()); | |
418 | decode_json_obj(val.get(), *iter); | |
9f95a23c | 419 | } catch (const err& e) { |
11fdf7f2 | 420 | val.reset(); |
9f95a23c TL |
421 | std::string s = std::string(name) + ": "; |
422 | s.append(e.what()); | |
11fdf7f2 TL |
423 | throw err(s); |
424 | } | |
425 | ||
426 | return true; | |
427 | } | |
428 | ||
7c673cae | 429 | template<class T> |
9f95a23c TL |
430 | bool JSONDecoder::decode_json(const char *name, std::optional<T>& val, JSONObj *obj, bool mandatory) |
431 | { | |
432 | JSONObjIter iter = obj->find_first(name); | |
433 | if (iter.end()) { | |
434 | if (mandatory) { | |
435 | std::string s = "missing mandatory field " + std::string(name); | |
436 | throw err(s); | |
437 | } | |
438 | val.reset(); | |
439 | return false; | |
440 | } | |
441 | ||
442 | try { | |
443 | val.emplace(); | |
444 | decode_json_obj(*val, *iter); | |
445 | } catch (const err& e) { | |
446 | val.reset(); | |
447 | std::string s = std::string(name) + ": "; | |
448 | s.append(e.what()); | |
449 | throw err(s); | |
450 | } | |
451 | ||
452 | return true; | |
453 | } | |
454 | ||
455 | class JSONEncodeFilter | |
456 | { | |
457 | public: | |
458 | class HandlerBase { | |
459 | public: | |
460 | virtual ~HandlerBase() {} | |
461 | ||
462 | virtual std::type_index get_type() = 0; | |
463 | virtual void encode_json(const char *name, const void *pval, ceph::Formatter *) const = 0; | |
464 | }; | |
465 | ||
466 | template <class T> | |
467 | class Handler : public HandlerBase { | |
468 | public: | |
469 | virtual ~Handler() {} | |
470 | ||
471 | std::type_index get_type() override { | |
472 | return std::type_index(typeid(const T&)); | |
473 | } | |
474 | }; | |
475 | ||
476 | private: | |
477 | std::map<std::type_index, HandlerBase *> handlers; | |
478 | ||
479 | public: | |
480 | void register_type(HandlerBase *h) { | |
481 | handlers[h->get_type()] = h; | |
482 | } | |
483 | ||
484 | template <class T> | |
485 | bool encode_json(const char *name, const T& val, ceph::Formatter *f) { | |
486 | auto iter = handlers.find(std::type_index(typeid(val))); | |
487 | if (iter == handlers.end()) { | |
488 | return false; | |
489 | } | |
490 | ||
491 | iter->second->encode_json(name, (const void *)&val, f); | |
492 | return true; | |
493 | } | |
494 | }; | |
495 | ||
496 | template<class T> | |
497 | static void encode_json_impl(const char *name, const T& val, ceph::Formatter *f) | |
7c673cae FG |
498 | { |
499 | f->open_object_section(name); | |
500 | val.dump(f); | |
501 | f->close_section(); | |
502 | } | |
503 | ||
9f95a23c TL |
504 | template<class T> |
505 | static void encode_json(const char *name, const T& val, ceph::Formatter *f) | |
506 | { | |
507 | JSONEncodeFilter *filter = static_cast<JSONEncodeFilter *>(f->get_external_feature_handler("JSONEncodeFilter")); | |
508 | ||
509 | if (!filter || | |
510 | !filter->encode_json(name, val, f)) { | |
511 | encode_json_impl(name, val, f); | |
512 | } | |
513 | } | |
514 | ||
7c673cae FG |
515 | class utime_t; |
516 | ||
1e59de90 | 517 | void encode_json(const char *name, std::string_view val, ceph::Formatter *f); |
9f95a23c | 518 | void encode_json(const char *name, const std::string& val, ceph::Formatter *f); |
7c673cae FG |
519 | void encode_json(const char *name, const char *val, ceph::Formatter *f); |
520 | void encode_json(const char *name, bool val, ceph::Formatter *f); | |
521 | void encode_json(const char *name, int val, ceph::Formatter *f); | |
522 | void encode_json(const char *name, unsigned val, ceph::Formatter *f); | |
523 | void encode_json(const char *name, long val, ceph::Formatter *f); | |
524 | void encode_json(const char *name, unsigned long val, ceph::Formatter *f); | |
525 | void encode_json(const char *name, long long val, ceph::Formatter *f); | |
526 | void encode_json(const char *name, const utime_t& val, ceph::Formatter *f); | |
9f95a23c | 527 | void encode_json(const char *name, const ceph::buffer::list& bl, ceph::Formatter *f); |
7c673cae FG |
528 | void encode_json(const char *name, long long unsigned val, ceph::Formatter *f); |
529 | ||
f67539c2 TL |
530 | void encode_json(const char *name, const ceph::real_time& val, ceph::Formatter *f); |
531 | void encode_json(const char *name, const ceph::coarse_real_time& val, ceph::Formatter *f); | |
532 | ||
7c673cae FG |
533 | template<class T> |
534 | static void encode_json(const char *name, const std::list<T>& l, ceph::Formatter *f) | |
535 | { | |
536 | f->open_array_section(name); | |
9f95a23c | 537 | for (auto iter = l.cbegin(); iter != l.cend(); ++iter) { |
7c673cae FG |
538 | encode_json("obj", *iter, f); |
539 | } | |
540 | f->close_section(); | |
541 | } | |
9f95a23c | 542 | |
7c673cae FG |
543 | template<class T> |
544 | static void encode_json(const char *name, const std::deque<T>& l, ceph::Formatter *f) | |
545 | { | |
546 | f->open_array_section(name); | |
9f95a23c | 547 | for (auto iter = l.cbegin(); iter != l.cend(); ++iter) { |
7c673cae FG |
548 | encode_json("obj", *iter, f); |
549 | } | |
550 | f->close_section(); | |
11fdf7f2 | 551 | } |
9f95a23c | 552 | |
11fdf7f2 TL |
553 | template<class T, class Compare = std::less<T> > |
554 | static void encode_json(const char *name, const std::set<T, Compare>& l, ceph::Formatter *f) | |
7c673cae FG |
555 | { |
556 | f->open_array_section(name); | |
9f95a23c | 557 | for (auto iter = l.cbegin(); iter != l.cend(); ++iter) { |
7c673cae FG |
558 | encode_json("obj", *iter, f); |
559 | } | |
560 | f->close_section(); | |
561 | } | |
562 | ||
1e59de90 | 563 | template<class T, class Compare, class Alloc> |
f67539c2 | 564 | static void encode_json(const char *name, |
1e59de90 | 565 | const boost::container::flat_set<T, Compare, Alloc>& l, |
f67539c2 TL |
566 | ceph::Formatter *f) |
567 | { | |
568 | f->open_array_section(name); | |
569 | for (auto iter = l.cbegin(); iter != l.cend(); ++iter) { | |
570 | encode_json("obj", *iter, f); | |
571 | } | |
572 | f->close_section(); | |
573 | } | |
574 | ||
7c673cae FG |
575 | template<class T> |
576 | static void encode_json(const char *name, const std::vector<T>& l, ceph::Formatter *f) | |
577 | { | |
578 | f->open_array_section(name); | |
9f95a23c | 579 | for (auto iter = l.cbegin(); iter != l.cend(); ++iter) { |
7c673cae FG |
580 | encode_json("obj", *iter, f); |
581 | } | |
582 | f->close_section(); | |
583 | } | |
584 | ||
9f95a23c | 585 | template<class K, class V, class C = std::less<K>> |
31f18b77 | 586 | static void encode_json(const char *name, const std::map<K, V, C>& m, ceph::Formatter *f) |
7c673cae FG |
587 | { |
588 | f->open_array_section(name); | |
9f95a23c | 589 | for (auto i = m.cbegin(); i != m.cend(); ++i) { |
7c673cae FG |
590 | f->open_object_section("entry"); |
591 | encode_json("key", i->first, f); | |
592 | encode_json("val", i->second, f); | |
593 | f->close_section(); | |
594 | } | |
595 | f->close_section(); | |
596 | } | |
597 | ||
f67539c2 TL |
598 | template<class K, class V, class C = std::less<K> > |
599 | static void encode_json(const char *name, const boost::container::flat_map<K, V, C>& m, ceph::Formatter *f) | |
600 | { | |
601 | f->open_array_section(name); | |
602 | for (auto i = m.cbegin(); i != m.cend(); ++i) { | |
603 | f->open_object_section("entry"); | |
604 | encode_json("key", i->first, f); | |
605 | encode_json("val", i->second, f); | |
606 | f->close_section(); | |
607 | } | |
608 | f->close_section(); | |
609 | } | |
610 | ||
7c673cae FG |
611 | template<class K, class V> |
612 | static void encode_json(const char *name, const std::multimap<K, V>& m, ceph::Formatter *f) | |
613 | { | |
614 | f->open_array_section(name); | |
9f95a23c TL |
615 | for (auto i = m.begin(); i != m.end(); ++i) { |
616 | f->open_object_section("entry"); | |
617 | encode_json("key", i->first, f); | |
618 | encode_json("val", i->second, f); | |
619 | f->close_section(); | |
620 | } | |
621 | f->close_section(); | |
622 | } | |
623 | ||
624 | template<class K, class V> | |
625 | static void encode_json(const char *name, const boost::container::flat_map<K, V>& m, ceph::Formatter *f) | |
626 | { | |
627 | f->open_array_section(name); | |
628 | for (auto i = m.begin(); i != m.end(); ++i) { | |
7c673cae FG |
629 | f->open_object_section("entry"); |
630 | encode_json("key", i->first, f); | |
631 | encode_json("val", i->second, f); | |
632 | f->close_section(); | |
633 | } | |
634 | f->close_section(); | |
635 | } | |
9f95a23c | 636 | |
7c673cae | 637 | template<class K, class V> |
9f95a23c | 638 | void encode_json_map(const char *name, const std::map<K, V>& m, ceph::Formatter *f) |
7c673cae FG |
639 | { |
640 | f->open_array_section(name); | |
9f95a23c | 641 | for (auto iter = m.cbegin(); iter != m.cend(); ++iter) { |
7c673cae FG |
642 | encode_json("obj", iter->second, f); |
643 | } | |
9f95a23c | 644 | f->close_section(); |
7c673cae FG |
645 | } |
646 | ||
647 | ||
648 | template<class K, class V> | |
649 | void encode_json_map(const char *name, const char *index_name, | |
650 | const char *object_name, const char *value_name, | |
651 | void (*cb)(const char *, const V&, ceph::Formatter *, void *), void *parent, | |
9f95a23c | 652 | const std::map<K, V>& m, ceph::Formatter *f) |
7c673cae FG |
653 | { |
654 | f->open_array_section(name); | |
9f95a23c | 655 | for (auto iter = m.cbegin(); iter != m.cend(); ++iter) { |
7c673cae FG |
656 | if (index_name) { |
657 | f->open_object_section("key_value"); | |
658 | f->dump_string(index_name, iter->first); | |
659 | } | |
660 | ||
661 | if (object_name) { | |
662 | f->open_object_section(object_name); | |
663 | } | |
664 | ||
665 | if (cb) { | |
666 | cb(value_name, iter->second, f, parent); | |
667 | } else { | |
668 | encode_json(value_name, iter->second, f); | |
669 | } | |
670 | ||
671 | if (object_name) { | |
672 | f->close_section(); | |
673 | } | |
674 | if (index_name) { | |
675 | f->close_section(); | |
676 | } | |
677 | } | |
678 | f->close_section(); | |
679 | } | |
680 | ||
681 | template<class K, class V> | |
682 | void encode_json_map(const char *name, const char *index_name, | |
683 | const char *object_name, const char *value_name, | |
9f95a23c | 684 | const std::map<K, V>& m, ceph::Formatter *f) |
7c673cae FG |
685 | { |
686 | encode_json_map<K, V>(name, index_name, object_name, value_name, NULL, NULL, m, f); | |
687 | } | |
688 | ||
689 | template<class K, class V> | |
690 | void encode_json_map(const char *name, const char *index_name, const char *value_name, | |
9f95a23c | 691 | const std::map<K, V>& m, ceph::Formatter *f) |
7c673cae FG |
692 | { |
693 | encode_json_map<K, V>(name, index_name, NULL, value_name, NULL, NULL, m, f); | |
694 | } | |
695 | ||
9f95a23c TL |
696 | template <class T> |
697 | static void encode_json(const char *name, const std::optional<T>& o, ceph::Formatter *f) | |
698 | { | |
699 | if (!o) { | |
700 | return; | |
701 | } | |
702 | encode_json(name, *o, f); | |
703 | } | |
704 | ||
705 | ||
f67539c2 TL |
706 | template<class K, class V> |
707 | void encode_json_map(const char *name, const boost::container::flat_map<K, V>& m, ceph::Formatter *f) | |
708 | { | |
709 | f->open_array_section(name); | |
710 | for (auto iter = m.cbegin(); iter != m.cend(); ++iter) { | |
711 | encode_json("obj", iter->second, f); | |
712 | } | |
713 | f->close_section(); | |
714 | } | |
715 | ||
716 | ||
717 | template<class K, class V> | |
718 | void encode_json_map(const char *name, const char *index_name, | |
719 | const char *object_name, const char *value_name, | |
720 | void (*cb)(const char *, const V&, ceph::Formatter *, void *), void *parent, | |
721 | const boost::container::flat_map<K, V>& m, ceph::Formatter *f) | |
722 | { | |
723 | f->open_array_section(name); | |
724 | for (auto iter = m.cbegin(); iter != m.cend(); ++iter) { | |
725 | if (index_name) { | |
726 | f->open_object_section("key_value"); | |
727 | f->dump_string(index_name, iter->first); | |
728 | } | |
729 | ||
730 | if (object_name) { | |
731 | f->open_object_section(object_name); | |
732 | } | |
733 | ||
734 | if (cb) { | |
735 | cb(value_name, iter->second, f, parent); | |
736 | } else { | |
737 | encode_json(value_name, iter->second, f); | |
738 | } | |
739 | ||
740 | if (object_name) { | |
741 | f->close_section(); | |
742 | } | |
743 | if (index_name) { | |
744 | f->close_section(); | |
745 | } | |
746 | } | |
747 | f->close_section(); | |
748 | } | |
749 | ||
750 | template<class K, class V> | |
751 | void encode_json_map(const char *name, const char *index_name, | |
752 | const char *object_name, const char *value_name, | |
753 | const boost::container::flat_map<K, V>& m, ceph::Formatter *f) | |
754 | { | |
755 | encode_json_map<K, V>(name, index_name, object_name, value_name, NULL, NULL, m, f); | |
756 | } | |
757 | ||
758 | template<class K, class V> | |
759 | void encode_json_map(const char *name, const char *index_name, const char *value_name, | |
760 | const boost::container::flat_map<K, V>& m, ceph::Formatter *f) | |
761 | { | |
762 | encode_json_map<K, V>(name, index_name, NULL, value_name, NULL, NULL, m, f); | |
763 | } | |
764 | ||
765 | ||
11fdf7f2 TL |
766 | class JSONFormattable : public ceph::JSONFormatter { |
767 | JSONObj::data_val value; | |
9f95a23c TL |
768 | std::vector<JSONFormattable> arr; |
769 | std::map<std::string, JSONFormattable> obj; | |
11fdf7f2 | 770 | |
9f95a23c | 771 | std::vector<JSONFormattable *> enc_stack; |
11fdf7f2 TL |
772 | JSONFormattable *cur_enc; |
773 | ||
774 | protected: | |
9f95a23c TL |
775 | bool handle_value(std::string_view name, std::string_view s, bool quoted) override; |
776 | bool handle_open_section(std::string_view name, const char *ns, bool section_is_array) override; | |
11fdf7f2 TL |
777 | bool handle_close_section() override; |
778 | ||
779 | public: | |
780 | JSONFormattable(bool p = false) : JSONFormatter(p) { | |
781 | cur_enc = this; | |
782 | enc_stack.push_back(cur_enc); | |
783 | } | |
784 | ||
785 | enum Type { | |
786 | FMT_NONE, | |
787 | FMT_VALUE, | |
788 | FMT_ARRAY, | |
789 | FMT_OBJ, | |
790 | } type{FMT_NONE}; | |
791 | ||
792 | void set_type(Type t) { | |
793 | type = t; | |
794 | } | |
795 | ||
796 | void decode_json(JSONObj *jo) { | |
797 | if (jo->is_array()) { | |
798 | set_type(JSONFormattable::FMT_ARRAY); | |
799 | decode_json_obj(arr, jo); | |
800 | } else if (jo->is_object()) { | |
801 | set_type(JSONFormattable::FMT_OBJ); | |
802 | auto iter = jo->find_first(); | |
803 | for (;!iter.end(); ++iter) { | |
804 | JSONObj *field = *iter; | |
805 | decode_json_obj(obj[field->get_name()], field); | |
806 | } | |
807 | } else { | |
808 | set_type(JSONFormattable::FMT_VALUE); | |
809 | decode_json_obj(value, jo); | |
810 | } | |
811 | } | |
812 | ||
9f95a23c | 813 | void encode(ceph::buffer::list& bl) const { |
11fdf7f2 TL |
814 | ENCODE_START(2, 1, bl); |
815 | encode((uint8_t)type, bl); | |
816 | encode(value.str, bl); | |
817 | encode(arr, bl); | |
818 | encode(obj, bl); | |
819 | encode(value.quoted, bl); | |
820 | ENCODE_FINISH(bl); | |
821 | } | |
822 | ||
9f95a23c | 823 | void decode(ceph::buffer::list::const_iterator& bl) { |
11fdf7f2 TL |
824 | DECODE_START(2, bl); |
825 | uint8_t t; | |
826 | decode(t, bl); | |
827 | type = (Type)t; | |
828 | decode(value.str, bl); | |
829 | decode(arr, bl); | |
830 | decode(obj, bl); | |
831 | if (struct_v >= 2) { | |
832 | decode(value.quoted, bl); | |
833 | } else { | |
834 | value.quoted = true; | |
835 | } | |
836 | DECODE_FINISH(bl); | |
837 | } | |
838 | ||
839 | const std::string& val() const { | |
840 | return value.str; | |
841 | } | |
842 | ||
843 | int val_int() const; | |
844 | long val_long() const; | |
845 | long long val_long_long() const; | |
846 | bool val_bool() const; | |
847 | ||
9f95a23c | 848 | const std::map<std::string, JSONFormattable> object() const { |
11fdf7f2 TL |
849 | return obj; |
850 | } | |
851 | ||
9f95a23c | 852 | const std::vector<JSONFormattable>& array() const { |
11fdf7f2 TL |
853 | return arr; |
854 | } | |
855 | ||
856 | const JSONFormattable& operator[](const std::string& name) const; | |
857 | const JSONFormattable& operator[](size_t index) const; | |
858 | ||
859 | JSONFormattable& operator[](const std::string& name); | |
860 | JSONFormattable& operator[](size_t index); | |
861 | ||
862 | operator std::string() const { | |
863 | return value.str; | |
864 | } | |
865 | ||
866 | explicit operator int() const { | |
867 | return val_int(); | |
868 | } | |
869 | ||
870 | explicit operator long() const { | |
871 | return val_long(); | |
872 | } | |
873 | ||
874 | explicit operator long long() const { | |
875 | return val_long_long(); | |
876 | } | |
877 | ||
878 | explicit operator bool() const { | |
879 | return val_bool(); | |
880 | } | |
881 | ||
882 | template<class T> | |
883 | T operator[](const std::string& name) const { | |
884 | return this->operator[](name)(T()); | |
885 | } | |
886 | ||
887 | template<class T> | |
888 | T operator[](const std::string& name) { | |
889 | return this->operator[](name)(T()); | |
890 | } | |
891 | ||
9f95a23c TL |
892 | std::string operator ()(const char *def_val) const { |
893 | return def(std::string(def_val)); | |
11fdf7f2 TL |
894 | } |
895 | ||
896 | int operator()(int def_val) const { | |
897 | return def(def_val); | |
898 | } | |
899 | ||
900 | bool operator()(bool def_val) const { | |
901 | return def(def_val); | |
902 | } | |
903 | ||
9f95a23c | 904 | bool exists(const std::string& name) const; |
11fdf7f2 TL |
905 | bool exists(size_t index) const; |
906 | ||
907 | std::string def(const std::string& def_val) const; | |
908 | int def(int def_val) const; | |
909 | bool def(bool def_val) const; | |
910 | ||
911 | bool find(const std::string& name, std::string *val) const; | |
912 | ||
913 | std::string get(const std::string& name, const std::string& def_val) const; | |
914 | ||
915 | int get_int(const std::string& name, int def_val) const; | |
916 | bool get_bool(const std::string& name, bool def_val) const; | |
917 | ||
9f95a23c TL |
918 | int set(const std::string& name, const std::string& val); |
919 | int erase(const std::string& name); | |
11fdf7f2 TL |
920 | |
921 | void derive_from(const JSONFormattable& jf); | |
922 | ||
9f95a23c | 923 | void encode_json(const char *name, ceph::Formatter *f) const; |
11fdf7f2 TL |
924 | |
925 | bool is_array() const { | |
926 | return (type == FMT_ARRAY); | |
927 | } | |
928 | }; | |
929 | WRITE_CLASS_ENCODER(JSONFormattable) | |
930 | ||
9f95a23c | 931 | void encode_json(const char *name, const JSONFormattable& v, ceph::Formatter *f); |
11fdf7f2 | 932 | |
7c673cae | 933 | #endif |