Decentralised Art Server
High-performance C++ backend that exposes HTML interface and a secure REST API for managing Performative Transactions entities
 
Loading...
Searching...
No Matches
route_arg.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <optional>
5#include <format>
6#include <cassert>
7#include <tuple>
8#include <vector>
9#include <list>
10#include <memory>
11#include <type_traits>
12
13#include <spdlog/spdlog.h>
14
15namespace dcn
16{
22 enum class RouteArgType
23 {
24 // Unknown
25 Unknown = 0,
26
29 base58,
30 string,
31 array,
32 object
33 };
34
41 {
42 // Unknown
43 Unknown = 0,
44
47 };
48
56 {
59
62
63 // Copy constructor (deep copy)
66 {
67 children.reserve(other.children.size());
68 for (const auto& child : other.children)
69 {
70 if (child)
71 children.emplace_back(std::make_unique<RouteArgDef>(*child));
72 else
73 children.emplace_back(nullptr);
74 }
75 }
76
77 // Move constructor
79 : type(std::move(other.type)), requirement(std::move(other.requirement)), children(std::move(other.children)) {}
80
83 std::vector<std::unique_ptr<RouteArgDef>> children;
84 };
85
93 {
94 public:
95 RouteArg(RouteArgDef def, std::string data);
96
102 RouteArgType getType() const;
103
109 const std::string & getData() const;
110
117
123 const std::vector<std::unique_ptr<RouteArgDef>> & getChildren() const;
124
125 private:
126
127 RouteArgDef _def;
128 std::string _data;
129 };
130}
131
132namespace dcn::parse
133{
134 constexpr static const char ARRAY_START_IDENTIFIER = '[';
135 constexpr static const char ARRAY_END_IDENTIFIER = ']';
136
137 constexpr static const unsigned int MAX_OBJECT_FIELDS = 5;
138 constexpr static const char OBJECT_START_IDENTIFIER = '(';
139 constexpr static const char OBJECT_END_IDENTIFIER = ')';
140 constexpr static const char OBJECT_FIELDS_DELIMETER = ';';
141
142 // Base check for presence of value_type and iterator
143 template<typename T>
144 concept HasValueTypeAndIterator = requires {
145 typename T::value_type;
146 typename T::iterator;
147 };
148
149 // General concept for STL-like containers
150 template<typename T>
152 (
153 std::is_array<T>::value ||
154 std::is_same_v<T, std::vector<typename T::value_type>> ||
155 std::is_same_v<T, std::list<typename T::value_type>>
156 );
157
158 template<typename T>
159 struct is_tuple_like_impl : std::false_type {};
160
161 template<typename... Ts>
162 struct is_tuple_like_impl<std::tuple<Ts...>> : std::true_type {};
163
164 template<typename T1, typename T2>
165 struct is_tuple_like_impl<std::pair<T1, T2>> : std::true_type {};
166
167 template<typename T>
168 concept IsTupleLike =
170 && std::tuple_size<T>::value > 0
171 && std::tuple_size<T>::value < MAX_OBJECT_FIELDS;
172
182 RouteArgType parseRouteArgTypeFromString(const std::string & str);
183
193 std::optional<RouteArgDef> parseRouteArgDefFromString(const std::string str);
194
195 template<class T>
197 std::optional<T> parseRouteArgAs(const RouteArg & arg);
198
208 template<>
209 std::optional<std::size_t> parseRouteArgAs<std::size_t>(const RouteArg & arg);
210
220 template<>
221 std::optional<std::uint32_t> parseRouteArgAs<std::uint32_t>(const RouteArg & arg);
222
232 template<>
233 std::optional<std::string> parseRouteArgAs<std::string>(const RouteArg & arg);
234
235
236 template <IsTupleLike TupleT, std::size_t Size>
237 struct TupleParser;
238
239 template <IsTupleLike TupleT>
240 struct TupleParser<TupleT, 2>
241 {
242 std::optional<TupleT> operator()(const std::vector<std::unique_ptr<dcn::RouteArgDef>> &defs, const std::vector<std::string> & values_str)
243 {
244 if(values_str.size() != std::tuple_size<TupleT>::value)return std::nullopt;
245 if(defs.size() != std::tuple_size<TupleT>::value)return std::nullopt;
246
249
250 if(!t0 || !t1)return std::nullopt;
251
252 return std::make_tuple(*t0, *t1);
253 }
254 };
255
256 template <IsTupleLike TupleT>
257 struct TupleParser<TupleT, 3>
258 {
259 std::optional<TupleT> operator()(const std::vector<std::unique_ptr<dcn::RouteArgDef>> &defs, const std::vector<std::string> & values_str)
260 {
261 if(values_str.size() != std::tuple_size<TupleT>::value)return std::nullopt;
262 if(defs.size() != std::tuple_size<TupleT>::value)return std::nullopt;
263
267
268 if(!t0 || !t1 || !t2)return std::nullopt;
269
270 return std::make_tuple(*t0, *t1, *t2);
271 }
272 };
273
274 template <IsTupleLike TupleT>
275 struct TupleParser<TupleT, 4>
276 {
277 std::optional<TupleT> operator()(const std::vector<std::unique_ptr<dcn::RouteArgDef>> &defs, const std::vector<std::string> & values_str)
278 {
279 if(values_str.size() != std::tuple_size<TupleT>::value)return std::nullopt;
280 if(defs.size() != std::tuple_size<TupleT>::value)return std::nullopt;
281
286
287 if(!t0 || !t1 || !t2 || !t3)return std::nullopt;
288
289 return std::make_tuple(*t0, *t1, *t2, *t3);
290 }
291 };
292
293
294 template<IsTupleLike TupleT>
295 std::optional<TupleT> parseRouteArgAs(const RouteArg& arg)
296 {
297 if(arg.getType() != RouteArgType::object)return std::nullopt;
298 if(std::tuple_size<TupleT>::value == 0) return std::nullopt;
299 if(arg.getChildren().size() != std::tuple_size<TupleT>::value) return std::nullopt;
300
301 std::string data = arg.getData();
302 if(data.empty())return std::nullopt;
303 if(data.front() != OBJECT_START_IDENTIFIER) return std::nullopt;
304 if(data.back() != OBJECT_END_IDENTIFIER) return std::nullopt;
305
306 // remove delimiters
307 data = data.substr(1, data.size() - 2);
308
309 // split arg into fields
310 std::vector<std::string> values_str;
311 std::size_t begin = 0;
312 std::size_t end = 0;
313
314 while ((end = data.find(OBJECT_FIELDS_DELIMETER, begin)) != std::string::npos) {
315 values_str.push_back(data.substr(begin, (end - begin)));
316 begin = end + 1;
317 }
318 // add the last value
319 values_str.push_back(data.substr(begin));
320
322 }
323
324 template<IsSequenceContainer ContainerT>
325 std::optional<ContainerT> parseRouteArgAs(const RouteArg& arg)
326 {
327 using T = typename ContainerT::value_type;
328
329 if(arg.getType() != RouteArgType::array)return std::nullopt;
330 if(arg.getChildren().size() != 1)return std::nullopt;
331 if(arg.getChildren().at(0) == nullptr)return std::nullopt;
332
333 std::string data = arg.getData();
334 if(data.empty())return std::nullopt;
335 if(data.front() != ARRAY_START_IDENTIFIER) return std::nullopt;
336 if(data.back() != ARRAY_END_IDENTIFIER) return std::nullopt;
337
338 // remove delimiters
339 data = data.substr(1, data.size() - 2);
340
341 // split arg into values
342 constexpr static const char array_values_delimeter = ',';
343
344 std::vector<std::string> values_str;
345 std::size_t begin = 0;
346 std::size_t end = 0;
347
348 while ((end = data.find(array_values_delimeter, begin)) != std::string::npos) {
349 values_str.push_back(data.substr(begin, (end - begin)));
350 begin = end + 1;
351 }
352 // add the last value
353 values_str.push_back(data.substr(begin));
354
356 const auto & array_type = *arg.getChildren().at(0);
357
358 for (const auto & value_str : values_str)
359 {
360 RouteArg array_value = RouteArg(array_type, value_str);
362 if(!parsed_value)return std::nullopt;
363 values.emplace_back(*parsed_value);
364 }
365
366 return values;
367 }
368
369
370}
371
372template <>
373struct std::formatter<dcn::RouteArgType> : std::formatter<std::string> {
374 auto format(const dcn::RouteArgType & arg_type, format_context& ctx) const {
375 switch(arg_type)
376 {
377 case dcn::RouteArgType::character: return formatter<string>::format("char", ctx);
378 case dcn::RouteArgType::unsigned_integer: return formatter<string>::format("uint", ctx);
379 case dcn::RouteArgType::string: return formatter<string>::format("string", ctx);
380 case dcn::RouteArgType::base58: return formatter<string>::format("base58", ctx);
381 case dcn::RouteArgType::array: return formatter<string>::format("array", ctx);
382 case dcn::RouteArgType::object: return formatter<string>::format("object", ctx);
383
384 // Unknown
385 case dcn::RouteArgType::Unknown: return formatter<string>::format("Unknown", ctx);
386 }
387 return formatter<string>::format("", ctx);
388 }
389};
390
391template <>
392struct std::formatter<dcn::RouteArgRequirement> : std::formatter<std::string> {
393 auto format(const dcn::RouteArgRequirement & req, format_context& ctx) const {
394 switch(req)
395 {
396 case dcn::RouteArgRequirement::required: return formatter<string>::format("required", ctx);
397 case dcn::RouteArgRequirement::optional: return formatter<string>::format("(optional)", ctx);
398
399 // Unknown
400 case dcn::RouteArgRequirement::Unknown: return formatter<string>::format("Unknown", ctx);
401 }
402 return formatter<string>::format("", ctx);
403 }
404};
405
406template <>
407struct std::formatter<dcn::RouteArg> : std::formatter<std::string> {
408 auto format(const dcn::RouteArg & arg, format_context& ctx) const {
409 return formatter<string>::format(
410 std::format("({}) [{}] {}", arg.getRequirement(), arg.getType(), arg.getData()), ctx);
411 }
412};
A class representing a route argument.
Definition route_arg.hpp:93
RouteArgType getType() const
Gets the type of the route argument.
Definition route_arg.cpp:12
RouteArgRequirement getRequirement() const
Gets the requirement of the route argument.
Definition route_arg.cpp:22
const std::string & getData() const
Gets the data associated with the route argument.
Definition route_arg.cpp:17
const std::vector< std::unique_ptr< RouteArgDef > > & getChildren() const
Gets the children of the route argument.
Definition route_arg.cpp:27
Definition route_arg.hpp:144
Definition route_arg.hpp:151
Definition route_arg.hpp:168
Definition auth.hpp:34
Definition decentralised_art.hpp:30
RouteArgRequirement
Enum to represent the requirement of a route argument.
Definition route_arg.hpp:41
RouteArgType
Enum to represent the type of a route argument.
Definition route_arg.hpp:23
A pair of RouteArgType and RouteArgRequirement.
Definition route_arg.hpp:56
RouteArgType type
Definition route_arg.hpp:81
RouteArgRequirement requirement
Definition route_arg.hpp:82
RouteArgDef(const RouteArgDef &other)
Definition route_arg.hpp:64
RouteArgDef(RouteArgDef &&other) noexcept
Definition route_arg.hpp:78
RouteArgDef(RouteArgType type, RouteArgRequirement requirement)
Definition route_arg.hpp:57
std::vector< std::unique_ptr< RouteArgDef > > children
Definition route_arg.hpp:83
RouteArgDef(RouteArgType type, RouteArgRequirement requirement, std::vector< std::unique_ptr< RouteArgDef > > children)
Definition route_arg.hpp:60
auto format(const dcn::RouteArgRequirement &req, format_context &ctx) const
Definition route_arg.hpp:393
auto format(const dcn::RouteArgType &arg_type, format_context &ctx) const
Definition route_arg.hpp:374
auto format(const dcn::RouteArg &arg, format_context &ctx) const
Definition route_arg.hpp:408