diff --git a/include/tgbot/bot.h b/include/tgbot/bot.h index 747e09b..f4719a9 100644 --- a/include/tgbot/bot.h +++ b/include/tgbot/bot.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -7,11 +8,35 @@ #include #include #include +#include #include #include +#define TBGOT_TO_JSON_REQUEST_MACRO(f, ret) \ + auto f(const f##Request &r) const { \ + nlohmann::json j; \ + boost::pfr::for_each_field(r, [&](auto &&field, std::integral_constant) { \ + to_json(j, boost::pfr::get_name(), field); \ + }); \ + j = send_request(#f, j.dump()); \ + return from_json(j); \ + } + +#define TBGOT_TO_REQUEST_ARGUMENT_REQUEST_MACRO(f, ret) \ + auto f(const f##Request &r) const { \ + std::array> args; \ + auto i = args.begin(); \ + boost::pfr::for_each_field(r, [&](auto &&field, std::integral_constant) { \ + to_request_argument(i, boost::pfr::get_name(), field); \ + }); \ + auto j = send_request(#f, http_request_arguments{args.begin(), i}); \ + return from_json(j); \ + } + namespace tgbot { +using namespace std::literals; + using Boolean = bool; using Integer = std::int64_t; using Float = double; @@ -71,7 +96,7 @@ struct api { // Bot's HttpClient must implement //std::string make_request(const std::string &url, const http_request_arguments &args) const; //std::string make_request(const std::string &url, const std::string &json) const; - nlohmann::json send_request(const char *method, auto &&args) const { + nlohmann::json send_request(std::string_view method, auto &&args) const { auto url = bot.base_url(); url += bot.token(); url += "/"; @@ -124,7 +149,7 @@ struct api { return a; } } - static void to_request_argument(auto &&arg, const char *n, auto &&r) { + static void to_request_argument(auto &&arg, std::string_view n, auto &&r) { if (auto v = to_request_argument(n, r); v) *arg++ = std::move(*v); } @@ -152,12 +177,14 @@ struct api { return j; } else { nlohmann::json j; - refl::for_each([&v, &j](auto n, auto f) {to_json(j, n, v.*f); }); + boost::pfr::for_each_field(v, [&](auto &&field, std::integral_constant) { + to_json(j, boost::pfr::get_name(), field); + }); return j; } } template - static void to_json(nlohmann::json &j, const char *k, const T &r) { + static void to_json(nlohmann::json &j, std::string_view k, const T &r) { if (auto v = to_json(r); !v.is_null()) j[k] = v; } @@ -183,12 +210,14 @@ struct api { return from_json(j, type{}); } else { T v; - refl::for_each([&v, &j](auto n, auto f) {from_json(j, n, v.*f); }); + boost::pfr::for_each_field(v, [&](auto &&field, std::integral_constant) { + from_json(j, boost::pfr::get_name(), field); + }); return v; } } template - static void from_json(const nlohmann::json &j, const char *k, T &v) { + static void from_json(const nlohmann::json &j, std::string_view k, T &v) { if (j.contains(k)) v = from_json(j[k]); } diff --git a/sw.cpp b/sw.cpp index 97c1eea..24d353e 100644 --- a/sw.cpp +++ b/sw.cpp @@ -24,6 +24,7 @@ void build(Solution &s) if (tgbot.getCompilerType() == CompilerType::MSVC) tgbot.Public.CompileOptions.push_back("/Zc:__cplusplus"); tgbot.Public += "org.sw.demo.nlohmann.json"_dep; + tgbot.Public += "org.sw.demo.boostorg.pfr-develop"_dep; { auto c = tgbot.addCommand(); c << cmd::prog(apitool) @@ -33,6 +34,9 @@ void build(Solution &s) << cmd::out("types.inl.h") << cmd::out("methods.inl.h") ; + // to make dependency? (in VS IDE only?) + //tgbot.Public += "types.inl.h"; + //tgbot.Public += "methods.inl.h"; } } diff --git a/tools/emitter.cpp b/tools/emitter.cpp index cb99364..dddf20c 100644 --- a/tools/emitter.cpp +++ b/tools/emitter.cpp @@ -223,13 +223,13 @@ void Method::emit(const Emitter &e, primitives::CppEmitter &h) const { cpp.addLine("std::array args;"); cpp.addLine("auto i = args.begin();"); for (auto &f: fields) - cpp.addLine("to_request_argument(i, \"" + f.name + "\", " + f.name + ");"); - cpp.addLine("auto j = send_request(\"" + name + "\", http_request_arguments{args.begin(), i});"); + cpp.addLine("to_request_argument(i, \"" + f.name + "\"sv, " + f.name + ");"); + cpp.addLine("auto j = send_request(\"" + name + "\"sv, http_request_arguments{args.begin(), i});"); } else { cpp.addLine("nlohmann::json j;"); for (auto &f: fields) - cpp.addLine("to_json(j, \"" + f.name + "\", " + f.name + ");"); - cpp.addLine("j = send_request(\"" + name + "\", j.dump());"); + cpp.addLine("to_json(j, \"" + f.name + "\"sv, " + f.name + ");"); + cpp.addLine("j = send_request(\"" + name + "\"sv, j.dump());"); } cpp.addLine(); cpp.addText("return from_json<"); @@ -241,16 +241,10 @@ void Method::emit(const Emitter &e, primitives::CppEmitter &h) const { // with request struct if (!fields.empty()) { cpp.addLine(); - cpp.addText("auto " + name + "(const " + cpp_name() + " &r) const"); - cpp.beginBlock(); - cpp.addLine("return " + name + "("); - cpp.increaseIndent(); - for (const auto &f: fields) - cpp.addLine("r." + f.name + ","); - cpp.trimEnd(1); - cpp.decreaseIndent(); - cpp.addLine(");"); - cpp.endBlock(); + cpp.addText((!has_input_file ? "TBGOT_TO_JSON_REQUEST_MACRO"s : "TBGOT_TO_REQUEST_ARGUMENT_REQUEST_MACRO"s) + + "(" + name + ", "); + return_type.emitFieldType(cpp, true, true); + cpp.addText(")"); cpp.emptyLines(); } } @@ -312,6 +306,7 @@ void Emitter::emitTypesHeader() { m.emitRequestType(ctx); } ctx.emptyLines(); + //write_file("types.inl.h", ctx.getText()); write_file("types.inl.h", ctx.getText() + emitReflection()); } @@ -408,21 +403,24 @@ String Emitter::emitReflection() const { ctx.addLine(); // refl for (auto &[n, t]: types) { + if (!t.is_received_variant(types)) { + continue; + } ctx.addLine("template <> struct refl<" + t.name + "> {"); ctx.increaseIndent(); - ctx.addLine("using T = " + t.name + ";"); - ctx.addLine(); + //ctx.addLine("using T = " + t.name + ";"); + //ctx.addLine(); ctx.addLine( "static constexpr auto is_received_variant = "s + (t.is_received_variant(types) ? "true" : "false") + ";"); //ctx.addLine("static constexpr auto size() { return " + std::to_string(t.fields.size()) + "; }"); - ctx.addLine(); + /*ctx.addLine(); ctx.addLine("template "); ctx.addLine("static void for_each(F &&f) {"); ctx.increaseIndent(); for (auto &f: t.fields) ctx.addLine("f(\"" + f.name + "\", &T::" + f.name + ");"); - ctx.endBlock(); + ctx.endBlock();*/ ctx.endBlock(true); ctx.emptyLines(); }