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
7#include <nlohmann/json.hpp>
8
9#include <memory>
10#include <optional>
11#include <string>
12#include <type_traits>
13#include <variant>
14#include <vector>
15
17
18namespace TgBot::ApiRequest {
19
20void appendField(std::vector<HttpFormField>& fields, const char* name, const std::string& value);
21void appendField(std::vector<HttpFormField>& fields, const char* name, const std::shared_ptr<InputFile>& value);
22
23template<typename T>
24void appendField(std::vector<HttpFormField>& fields, const char* name, const T& value) {
25 if constexpr (std::is_arithmetic_v<T>) {
26 fields.push_back({ name, std::to_string(value) });
27 } else {
28 fields.push_back({ name, Json::encode(value).dump() });
29 }
30}
31
32template<typename T>
33void appendField(std::vector<HttpFormField>& fields, const char* name, const std::optional<T>& value) {
34 if (value) {
35 appendField(fields, name, *value);
36 }
37}
38
39template<typename T>
40void appendField(std::vector<HttpFormField>& fields, const char* name, const std::shared_ptr<T>& value) {
41 if (value) {
42 fields.push_back({ name, Json::encode(value).dump() });
43 }
44}
45
46template<typename... T>
47void appendField(std::vector<HttpFormField>& fields, const char* name, const std::variant<T...>& value) {
48 std::visit(
49 [&](const auto& item) {
50 appendField(fields, name, item);
51 },
52 value);
53}
54
55template<typename T>
56requires std::is_arithmetic_v<T>
57void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, T value) {
58 if (value != 0) {
59 appendField(fields, name, value);
60 }
61}
62
63void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, const std::string& value);
64void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, const nlohmann::json& value);
65
66template<typename T>
67void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, const std::shared_ptr<T>& value) {
68 if (value) {
69 appendField(fields, name, value);
70 }
71}
72
73template<typename T>
74void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, const std::vector<T>& value) {
75 if (!value.empty()) {
76 appendField(fields, name, value);
77 }
78}
79
80template<typename... T>
81void appendOptionalField(std::vector<HttpFormField>& fields, const char* name, const std::variant<T...>& value) {
82 std::visit(
83 [&](const auto& item) {
84 appendOptionalField(fields, name, item);
85 },
86 value);
87}
88
89template<bool Required, typename T>
90struct Parameter {
91 static constexpr bool isRequired = Required;
92
93 const char* name;
94 const T& value;
95};
96
97template<typename T>
98struct ParameterWithDefault {
99 static constexpr bool isRequired = false;
100
101 const char* name;
102 const T& value;
103 T defaultValue;
104};
105
106template<typename T>
107Parameter<true, T> required(const char* name, const T& value) {
108 return { name, value };
109}
110
111template<typename T>
112Parameter<false, T> optional(const char* name, const T& value) {
113 return { name, value };
114}
115
116template<typename T>
117ParameterWithDefault<T> optional(const char* name, const T& value, T defaultValue) {
118 return { name, value, std::move(defaultValue) };
119}
120
121template<typename... Parameters>
122std::vector<HttpFormField> makeFields(const Parameters&... parameters) {
123 std::vector<HttpFormField> result;
124 result.reserve(sizeof...(Parameters));
125 (
126 [&] {
127 if constexpr (Parameters::isRequired) {
128 appendField(result, parameters.name, parameters.value);
129 } else if constexpr (requires { parameters.defaultValue; }) {
130 if (parameters.value != parameters.defaultValue) {
131 appendField(result, parameters.name, parameters.value);
132 }
133 } else {
134 appendOptionalField(result, parameters.name, parameters.value);
135 }
136 }(),
137 ...);
138
139 return result;
140}
141
142} // namespace TgBot::ApiRequest
143
144namespace TgBot::ApiResponse {
145
146template<typename T>
147T decode(const nlohmann::json& json) {
148 T result { };
149 Json::decode(json, result);
150
151 return result;
152}
153
154template<typename T>
155std::shared_ptr<T> decodeObjectOrTrue(const nlohmann::json& json) {
156 auto result = decode<std::variant<std::shared_ptr<T>, bool>>(json);
157 if (auto object = std::get_if<std::shared_ptr<T>>(&result)) {
158 return *object;
159 }
160
161 return nullptr;
162}
163
164} // namespace TgBot::ApiResponse
165