tgbot-cpp
Loading...
Searching...
No Matches
ApiCodec.h
Go to the documentation of this file.
1#pragma once
2
4#include "tgbot/InputFile.h"
5#include "tgbot/Json.h"
6#include "tgbot/export.h"
7
8#include <nlohmann/json.hpp>
9
10#include <memory>
11#include <optional>
12#include <stdexcept>
13#include <string>
14#include <string_view>
15#include <type_traits>
16#include <unordered_set>
17#include <variant>
18#include <vector>
19
21
22namespace TgBot::ApiRequest {
23
24TGBOT_API void appendField(std::vector<HttpFormField>& fields, std::string_view name, std::string_view value);
25TGBOT_API void appendField(std::vector<HttpFormField>& fields, std::string_view name,
26 const std::shared_ptr<InputFile>& value);
27
28template<typename T>
29requires(!std::is_convertible_v<const T&, std::string_view>)
30void appendField(std::vector<HttpFormField>& fields, std::string_view name, const T& value) {
31 if constexpr (std::is_arithmetic_v<T>) {
32 fields.push_back({ std::string(name), std::to_string(value) });
33 } else {
34 fields.push_back({ std::string(name), Json::encode(value).dump() });
35 }
36}
37
38template<typename T>
39void appendField(std::vector<HttpFormField>& fields, std::string_view name, const std::optional<T>& value) {
40 if (value) {
41 appendField(fields, name, *value);
42 }
43}
44
45template<typename T>
46void appendField(std::vector<HttpFormField>& fields, std::string_view name, const std::shared_ptr<T>& value) {
47 if (value) {
48 fields.push_back({ std::string(name), Json::encode(value).dump() });
49 }
50}
51
52template<typename... T>
53void appendField(std::vector<HttpFormField>& fields, std::string_view name, const std::variant<T...>& value) {
54 std::visit(
55 [&](const auto& item) {
56 appendField(fields, name, item);
57 },
58 value);
59}
60
61template<typename T>
62requires std::is_arithmetic_v<T>
63void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, T value) {
64 if (value != 0) {
65 appendField(fields, name, value);
66 }
67}
68
69TGBOT_API void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, std::string_view value);
70TGBOT_API void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, const std::string& value);
71
72TGBOT_API void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name,
73 const nlohmann::json& value);
74TGBOT_API void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name,
75 const std::vector<InputFileAttachment>& value);
76
77template<typename T>
78void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, const std::shared_ptr<T>& value) {
79 if (value) {
80 appendField(fields, name, value);
81 }
82}
83
84template<typename T>
85void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, const std::vector<T>& value) {
86 if (!value.empty()) {
87 appendField(fields, name, value);
88 }
89}
90
91template<typename... T>
92void appendOptionalField(std::vector<HttpFormField>& fields, std::string_view name, const std::variant<T...>& value) {
93 std::visit(
94 [&](const auto& item) {
95 appendOptionalField(fields, name, item);
96 },
97 value);
98}
99
106template<bool Required, typename T>
107struct Parameter {
108 static constexpr bool isRequired = Required;
109
110 std::string_view name;
111 const T& value;
112};
113
120template<typename T>
121struct ParameterWithDefault {
122 static constexpr bool isRequired = false;
123
124 std::string_view name;
125 const T& value;
126 T defaultValue;
127};
128
129template<typename T>
130Parameter<true, T> required(std::string_view name, const T& value) {
131 return { name, value };
132}
133
134template<typename T>
135Parameter<false, T> optional(std::string_view name, const T& value) {
136 return { name, value };
137}
138
139template<typename T>
140ParameterWithDefault<T> optional(std::string_view name, const T& value, T defaultValue) {
141 return { name, value, std::move(defaultValue) };
142}
143
144template<typename... Parameters>
145std::vector<HttpFormField> makeFields(const Parameters&... parameters) {
146 std::vector<HttpFormField> result;
147 result.reserve(sizeof...(Parameters));
148 (
149 [&] {
150 if constexpr (Parameters::isRequired) {
151 appendField(result, parameters.name, parameters.value);
152 } else if constexpr (requires { parameters.defaultValue; }) {
153 if (parameters.value != parameters.defaultValue) {
154 appendField(result, parameters.name, parameters.value);
155 }
156 } else {
157 appendOptionalField(result, parameters.name, parameters.value);
158 }
159 }(),
160 ...);
161
162 std::unordered_set<std::string_view> names;
163 for (const auto& field : result) {
164 if (!names.emplace(field.name).second) {
165 throw std::invalid_argument("Duplicate multipart field name: " + field.name);
166 }
167 }
168
169 return result;
170}
171
172} // namespace TgBot::ApiRequest
173
174namespace TgBot::ApiResponse {
175
176template<typename T>
177T decode(const nlohmann::json& json) {
178 T result { };
179 Json::decode(json, result);
180
181 return result;
182}
183
184template<typename T>
185std::shared_ptr<T> decodeObjectOrTrue(const nlohmann::json& json) {
186 auto result = decode<std::variant<std::shared_ptr<T>, bool>>(json);
187 if (auto object = std::get_if<std::shared_ptr<T>>(&result)) {
188 return *object;
189 }
190
191 return nullptr;
192}
193
194} // namespace TgBot::ApiResponse
195
#define TGBOT_API
Definition export.h:5