tgbotxx 1.2.9.5
Telegram Bot C++ Library
Loading...
Searching...
No Matches
Object.hpp
Go to the documentation of this file.
1#pragma once
3#include <type_traits>
4#include <cstdint>
5#include <ctime>
6#include <iostream>
7#include <memory>
8#include <nlohmann/json.hpp>
9#include <sstream>
10#include <string>
11#include <tgbotxx/Exception.hpp>
12#include <tgbotxx/utils/Ptr.hpp>
13#include <vector>
14namespace nl = nlohmann;
15
17
18
20#define TGBOTXX_CAT_IMPL(a, b) a##b
21#define TGBOTXX_CAT(a, b) TGBOTXX_CAT_IMPL(a, b)
22
24#define VAR(x) TGBOTXX_CAT(x, __LINE__)
25
27#define OBJECT_SERIALIZE_FIELD(json, json_field, field) \
28 do { \
29 json[json_field] = field; \
30 } while (false)
31
32#define OBJECT_SERIALIZE_FIELD_PTR(json, json_field, field) \
33 do { \
34 if (field) { \
35 json[json_field] = (field)->toJson(); \
36 } \
37 } while (false)
38
39#define OBJECT_SERIALIZE_FIELD_PTR_ARRAY(json, json_field, array_field) \
40 do { \
41 auto arr = json[json_field] = nl::json::array(); \
42 for (const auto& e: array_field) \
43 arr.emplace_back(e->toJson()); \
44 } while (false)
45
46#define OBJECT_SERIALIZE_FIELD_PTR_ARRAY_ARRAY(json, json_field, array_array_field) \
47 do { \
48 auto& root_arr = json[json_field] = nl::json::array(); \
49 for (const auto& array: array_array_field) { \
50 nl::json arr = nl::json::array(); \
51 for (const auto& e: array) { \
52 arr.emplace_back(e->toJson()); \
53 } \
54 root_arr.emplace_back(arr); \
55 } \
56 } while (false)
57
58#define OBJECT_SERIALIZE_FIELD_ENUM(json, enum_name, json_field, field) \
59 do { \
60 json[json_field] = TGBOTXX_CAT(enum_name, ToString)(field); \
61 } while (false)
62
64#define OBJECT_DESERIALIZE_FIELD(json, json_field, field, default_value, optional) \
65 do { \
66 if (json.contains(json_field)) { \
67 try { \
68 using T = std::remove_reference_t<std::remove_const_t<decltype(field)>>; \
69 field = json[json_field].get<T>(); \
70 } catch (const std::exception& e) { \
71 std::ostringstream err{}; \
72 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Failed to deserialize \"" \
73 << json_field << "\" from json object: " << json.dump(2) << "\nReason: " << e.what(); \
74 throw Exception(err.str()); \
75 } catch (...) { \
76 std::ostringstream err{}; \
77 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Failed to deserialize \"" \
78 << json_field << "\" from json object: " << json.dump(2); \
79 throw Exception(err.str()); \
80 } \
81 } else { \
82 if (not(optional)) { \
83 std::ostringstream err{}; \
84 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Missing required field \"" \
85 << json_field << "\" from json object: " << json.dump(2); \
86 throw Exception(err.str()); \
87 } \
88 field = default_value; \
89 } \
90 } while (false)
91
92#define OBJECT_DESERIALIZE_FIELD_PTR(json, json_field, field, optional) \
93 do { \
94 static_assert(!std::is_const_v<decltype(field)>, "OBJECT_DESERIALIZE_FIELD_PTR: 'field' must not be const"); \
95 static_assert(std::is_same_v<decltype(optional), bool>, "OBJECT_DESERIALIZE_FIELD_PTR: 'optional' must be boolean"); \
96 if (json.contains(json_field) and json[json_field].is_object() and not json[json_field].empty()) { \
97 using T = std::remove_reference_t<decltype(field)>; \
98 using E = T::element_type; \
99 field = makePtr<E>(json[json_field]); \
100 } else { \
101 if (not(optional)) { \
102 std::ostringstream err{}; \
103 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Missing required field \"" \
104 << json_field << "\" from json object: " << json.dump(2); \
105 throw Exception(err.str()); \
106 } \
107 field = nullptr; \
108 } \
109 } while (false)
110
111#define OBJECT_DESERIALIZE_FIELD_PTR_ARRAY(json, json_field, array_field, optional) \
112 do { \
113 static_assert(!std::is_const_v<decltype(array_field)>, "OBJECT_DESERIALIZE_FIELD_PTR_ARRAY: 'field' must not be const"); \
114 static_assert(std::is_same_v<decltype(optional), bool>, "OBJECT_DESERIALIZE_FIELD_PTR_ARRAY: 'optional' must be boolean"); \
115 if ((json.contains(json_field)) and (json[json_field].is_array())) { \
116 using T = std::remove_reference_t<std::remove_const_t<decltype(array_field)::value_type>>; \
117 using E = T::element_type; \
118 array_field.clear(); \
119 array_field.reserve(json[json_field].size()); \
120 for (const nl::json& obj: json[json_field]) { \
121 array_field.emplace_back(new E(obj)); \
122 } \
123 } else { \
124 if (not(optional)) { \
125 std::ostringstream err{}; \
126 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Missing required field \"" \
127 << json_field << "\" from json object: " << json.dump(2); \
128 throw Exception(err.str()); \
129 } \
130 array_field.clear(); \
131 } \
132 } while (false)
133
134
135#define OBJECT_DESERIALIZE_FIELD_PTR_ARRAY_ARRAY(json, json_field, array_array_field, optional) \
136 do { \
137 static_assert(!std::is_const_v<decltype(array_array_field)>, "OBJECT_DESERIALIZE_FIELD_PTR_ARRAY_ARRAY: 'field' must not be const"); \
138 static_assert(std::is_same_v<decltype(optional), bool>, "OBJECT_DESERIALIZE_FIELD_PTR_ARRAY_ARRAY: 'optional' must be boolean"); \
139 if ((json.contains(json_field)) and (json[json_field].is_array())) { \
140 using ArrayArray = decltype(array_array_field); \
141 using Array = ArrayArray::value_type; /* e.g vector<vector<int> <- > */ \
142 using T = ArrayArray::value_type::value_type; /* e.g vector<vector<int>> <- */ \
143 using E = T::element_type; \
144 array_array_field.clear(); \
145 array_array_field.reserve(json[json_field].size()); \
146 for (const nl::json& array: json[json_field]) { \
147 Array arr; \
148 arr.reserve(array.size()); \
149 for (const nl::json& obj: array) { \
150 arr.emplace_back(new E(obj)); \
151 } \
152 array_array_field.emplace_back(std::move(arr)); \
153 } \
154 } else { \
155 if (not(optional)) { \
156 std::ostringstream err{}; \
157 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Missing required field \"" \
158 << json_field << "\" from json object: " << json.dump(2); \
159 throw Exception(err.str()); \
160 } \
161 array_array_field.clear(); \
162 } \
163 } while (false)
164
165#define OBJECT_DESERIALIZE_FIELD_ENUM(json, enum_name, json_field, field, default_value, optional) \
166 do { \
167 static_assert(std::is_enum_v<decltype(field)>, "OBJECT_DESERIALIZE_FIELD_ENUM: 'field' must be an enum"); \
168 static_assert(!std::is_const_v<decltype(field)>, "OBJECT_DESERIALIZE_FIELD_ENUM: 'field' must not be const"); \
169 if (json.contains(json_field)) { \
170 try { \
171 if (auto opt = TGBOTXX_CAT(StringTo, enum_name)(json[json_field])) \
172 field = *opt; \
173 else \
174 throw Exception("Could not convert string \"" + json[json_field].get<std::string>() + "\" to enum"); \
175 } catch (const std::exception& e) { \
176 std::ostringstream err{}; \
177 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Failed to deserialize \"" \
178 << json_field << "\" from json object: " << json.dump(2) << "\nReason: " << e.what(); \
179 throw Exception(err.str()); \
180 } catch (...) { \
181 std::ostringstream err{}; \
182 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Failed to deserialize \"" \
183 << json_field << "\" from json object: " << json.dump(2); \
184 throw Exception(err.str()); \
185 } \
186 } else { \
187 if (not(optional)) { \
188 std::ostringstream err{}; \
189 err << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ": Missing required field \"" \
190 << json_field << "\" from json object: " << json.dump(2); \
191 throw Exception(err.str()); \
192 } \
193 field = static_cast<enum_name>(default_value); \
194 } \
195 } while (false)