]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/json/json_elements.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / json / json_elements.hh
CommitLineData
11fdf7f2
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18/*
19 * Copyright 2015 Cloudius Systems
20 */
21
22#pragma once
23
24#include <string>
25#include <vector>
26#include <time.h>
27#include <sstream>
f67539c2
TL
28#include <seastar/core/do_with.hh>
29#include <seastar/core/loop.hh>
11fdf7f2
TL
30#include <seastar/json/formatter.hh>
31#include <seastar/core/sstring.hh>
32#include <seastar/core/iostream.hh>
33
34namespace seastar {
35
36namespace json {
37
38/**
39 * The base class for all json element.
40 * Every json element has a name
41 * An indication if it was set or not
42 * And is this element is mandatory.
43 * When a mandatory element is not set
44 * this is not a valid object
45 */
46class json_base_element {
47public:
48 /**
49 * The constructors
50 */
20effc67 51 json_base_element() noexcept
11fdf7f2
TL
52 : _mandatory(false), _set(false) {
53 }
54
55 virtual ~json_base_element() = default;
56
57 /**
58 * Check if it's a mandatory parameter
59 * and if it's set.
60 * @return true if this is not a mandatory parameter
61 * or if it is and it's value is set
62 */
20effc67 63 virtual bool is_verify() noexcept {
11fdf7f2
TL
64 return !(_mandatory && !_set);
65 }
66
20effc67 67 json_base_element& operator=(const json_base_element& o) noexcept {
11fdf7f2
TL
68 // Names and mandatory are never changed after creation
69 _set = o._set;
70 return *this;
71 }
72
73 /**
74 * returns the internal value in a json format
75 * Each inherit class must implement this method
76 * @return formated internal value
77 */
78 virtual std::string to_string() = 0;
79
80 virtual future<> write(output_stream<char>& s) const = 0;
81 std::string _name;
82 bool _mandatory;
83 bool _set;
84};
85
86/**
87 * Basic json element instantiate
88 * the json_element template.
89 * it adds a value to the base definition
90 * and the to_string implementation using the formatter
91 */
92template<class T>
93class json_element : public json_base_element {
94public:
95
96 /**
97 * the assignment operator also set
98 * the set value to true.
99 * @param new_value the new value
100 * @return the value itself
101 */
102 json_element &operator=(const T& new_value) {
103 _value = new_value;
104 _set = true;
105 return *this;
106 }
107 /**
108 * the assignment operator also set
109 * the set value to true.
110 * @param new_value the new value
111 * @return the value itself
112 */
113 template<class C>
114 json_element &operator=(const C& new_value) {
115 _value = new_value;
116 _set = true;
117 return *this;
118 }
119 /**
120 * The brackets operator
121 * @return the value
122 */
20effc67 123 const T& operator()() const noexcept {
11fdf7f2
TL
124 return _value;
125 }
126
127 /**
128 * The to_string return the value
129 * formated as a json value
130 * @return the value foramted for json
131 */
132 virtual std::string to_string() override
133 {
134 return formatter::to_json(_value);
135 }
136
137 virtual future<> write(output_stream<char>& s) const override {
138 return formatter::write(s, _value);
139 }
140private:
141 T _value;
142};
143
144/**
145 * json_list is based on std vector implementation.
146 *
147 * When values are added with push it is set the "set" flag to true
148 * hence will be included in the parsed object
149 */
150template<class T>
151class json_list : public json_base_element {
152public:
153
154 /**
155 * Add an element to the list.
156 * @param element a new element that will be added to the list
157 */
158 void push(const T& element) {
159 _set = true;
160 _elements.push_back(element);
161 }
162
163 virtual std::string to_string() override
164 {
165 return formatter::to_json(_elements);
166 }
167
168 /**
169 * Assignment can be done from any object that support const range
170 * iteration and that it's elements can be assigned to the list elements
171 */
172 template<class C>
173 json_list& operator=(const C& list) {
174 _elements.clear();
175 for (auto i : list) {
176 push(i);
177 }
178 return *this;
179 }
180 virtual future<> write(output_stream<char>& s) const override {
181 return formatter::write(s, _elements);
182 }
183 std::vector<T> _elements;
184};
185
186class jsonable {
187public:
188 virtual ~jsonable() = default;
189 /**
190 * create a foramted string of the object.
191 * @return the object formated.
192 */
193 virtual std::string to_json() const = 0;
194
195 /*!
196 * \brief write an object to the output stream
197 *
198 * The defult implementation uses the to_json
199 * Object implementation override it.
200 */
201 virtual future<> write(output_stream<char>& s) const {
202 return s.write(to_json());
203 }
204};
205
206/**
207 * The base class for all json objects
208 * It holds a list of all the element in it,
209 * allowing it implement the to_json method.
210 *
211 * It also allows iterating over the element
212 * in the object, even if not all the member
213 * are known in advance and in practice mimic
214 * reflection
215 */
216struct json_base : public jsonable {
217
218 virtual ~json_base() = default;
219
220 json_base() = default;
221
222 json_base(const json_base&) = delete;
223
224 json_base operator=(const json_base&) = delete;
225
226 /**
227 * create a foramted string of the object.
228 * @return the object formated.
229 */
230 virtual std::string to_json() const;
231
232 /*!
233 * \brief write to an output stream
234 */
235 virtual future<> write(output_stream<char>&) const;
236
237 /**
238 * Check that all mandatory elements are set
239 * @return true if all mandatory parameters are set
240 */
241 virtual bool is_verify() const;
242
243 /**
244 * Register an element in an object
245 * @param element the element to be added
246 * @param name the element name
247 * @param mandatory is this element mandatory.
248 */
249 virtual void add(json_base_element* element, std::string name,
250 bool mandatory = false);
251
252 std::vector<json_base_element*> _elements;
253};
254
255/**
256 * There are cases where a json request needs to return a successful
257 * empty reply.
258 * The json_void class will be used to mark that the reply should be empty.
259 *
260 */
261struct json_void : public jsonable{
262 virtual std::string to_json() const {
263 return "";
264 }
265
266 /*!
267 * \brief write to an output stream
268 */
269 virtual future<> write(output_stream<char>& s) const {
270 return s.close();
271 }
272};
273
274
275/**
276 * The json return type, is a helper class to return a json
277 * formatted string.
278 * It uses autoboxing in its constructor so when a function return
279 * type is json_return_type, it could return a type that would be converted
280 * ie.
281 * json_return_type foo() {
282 * return "hello";
283 * }
284 *
285 * would return a json formatted string: "hello" (rather then hello)
286 */
287struct json_return_type {
288 sstring _res;
289 std::function<future<>(output_stream<char>&&)> _body_writer;
290 json_return_type(std::function<future<>(output_stream<char>&&)>&& body_writer) : _body_writer(std::move(body_writer)) {
291 }
292 template<class T>
293 json_return_type(const T& res) {
294 _res = formatter::to_json(res);
295 }
296
297 json_return_type(json_return_type&& o) noexcept : _res(std::move(o._res)), _body_writer(std::move(o._body_writer)) {
298 }
9f95a23c 299 json_return_type& operator=(json_return_type&& o) noexcept {
1e59de90
TL
300 if (this != &o) {
301 _res = std::move(o._res);
302 _body_writer = std::move(o._body_writer);
303 }
9f95a23c
TL
304 return *this;
305 }
20effc67
TL
306
307 json_return_type(const json_return_type&) = default;
308 json_return_type& operator=(const json_return_type&) = default;
11fdf7f2
TL
309};
310
311/*!
312 * \brief capture a range and return a serialize function for it as a json array.
313 *
314 * To use it, pass a range and a mapping function.
315 * For example, if res is a map:
316 *
317 * return make_ready_future<json::json_return_type>(stream_range_as_array(res, [](const auto&i) {return i.first}));
318 */
319template<typename Container, typename Func>
f67539c2 320SEASTAR_CONCEPT( requires requires (Container c, Func aa, output_stream<char> s) { { formatter::write(s, aa(*c.begin())) } -> std::same_as<future<>>; } )
11fdf7f2 321std::function<future<>(output_stream<char>&&)> stream_range_as_array(Container val, Func fun) {
1e59de90 322 return [val = std::move(val), fun = std::move(fun)](output_stream<char>&& s) mutable {
11fdf7f2
TL
323 return do_with(output_stream<char>(std::move(s)), Container(std::move(val)), Func(std::move(fun)), true, [](output_stream<char>& s, const Container& val, const Func& f, bool& first){
324 return s.write("[").then([&val, &s, &first, &f] () {
325 return do_for_each(val, [&s, &first, &f](const typename Container::value_type& v){
326 auto fut = first ? make_ready_future<>() : s.write(", ");
327 first = false;
328 return fut.then([&s, &f, &v]() {
329 return formatter::write(s, f(v));
330 });
331 });
332 }).then([&s](){
1e59de90
TL
333 return s.write("]");
334 }).finally([&s] {
335 return s.close();
11fdf7f2
TL
336 });
337 });
338 };
339}
340
341/*!
342 * \brief capture an object and return a serialize function for it.
343 *
344 * To use it:
345 * return make_ready_future<json::json_return_type>(stream_object(res));
346 */
347template<class T>
348std::function<future<>(output_stream<char>&&)> stream_object(T val) {
1e59de90 349 return [val = std::move(val)](output_stream<char>&& s) mutable {
11fdf7f2 350 return do_with(output_stream<char>(std::move(s)), T(std::move(val)), [](output_stream<char>& s, const T& val){
1e59de90 351 return formatter::write(s, val).finally([&s] {
11fdf7f2
TL
352 return s.close();
353 });
354 });
355 };
356}
357
358}
359
360}