-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Example for a structure of Application class with methods for setting up routes for APIs and Views.
#include <iostream>
#include <future>
#include <type_traits>
#include <string>
#include <string_view>
#include <vector>
#include <tuple>
#include <functional>
#include <algorithm>
#include <array>
// FixedString for NTTP string literals
template <size_t N>
struct FixedString {
char value[N];
constexpr FixedString(const char(&str)[N]) {
std::copy_n(str, N, value);
}
constexpr operator std::string_view() const {
return std::string_view(value);
}
};
// Compile-time id generator
template<size_t Id>
struct counter {
using tag = counter;
struct generator {
friend constexpr bool is_defined(tag) // The line that might cause a warning
{
return true;
}
};
friend constexpr bool is_defined(tag);
template<typename Tag = tag, bool = is_defined(Tag{}) >
static constexpr bool exists(auto)
{
return true;
}
static constexpr bool exists(...)
{
return generator(), false;
}
};
template<size_t Id = 0, typename = decltype([] {}) >
constexpr size_t unique_id() {
if constexpr (not counter<Id>::exists(Id)) return Id;
else return unique_id < Id + 1, decltype([] {}) > ();
}
// ---------- API Definition ----------
template <FixedString name, typename F>
struct ApiResponse;
template <size_t app_id, FixedString name, typename F>
struct ApiResponseRegister;
template <FixedString name, typename FRet, typename... FArgs>
struct ApiResponse<name, FRet(FArgs...)> {
static constexpr auto name_template = name;
static constexpr std::string_view name_str = name;
using Ret = FRet;
using Args = std::tuple<FArgs...>;
ApiResponse() {}
virtual std::future<FRet> get_future(FArgs...) const = 0;
};
template <size_t app_id, FixedString name, typename FRet, typename... FArgs>
struct ApiResponseRegister<app_id, name, FRet(FArgs...)> : public ApiResponse<name, FRet(FArgs...)> {
static std::function<FRet(FArgs...)> func;
std::future<FRet> future;
ApiResponseRegister() : ApiResponse<name, FRet(FArgs...)>() {}
virtual std::future<FRet> get_future(FArgs... args) const override
{
return std::async(func, args...);
}
};
template <size_t app_id, FixedString name, typename FRet, typename... FArgs>
std::function<FRet(FArgs...)> ApiResponseRegister<app_id, name, FRet(FArgs...)>::func;
// ---------- Application Class ----------
template <size_t _id = unique_id<size_t{}, decltype([] {})>()>
class Application {
private:
// Store API routes
std::unordered_map<std::string, std::function<void()>> api_routes;
// Store view routes
std::unordered_map<std::string, std::function<void()>> view_routes;
public:
Application() noexcept : api_routes(), view_routes()
{
}
Application& operator=(const Application&) = delete;
std::string render(std::string file, std::vector<std::string> params)
{
return " Hello World! " + file + " " + std::to_string(params.size());
}
template<FixedString name, typename Ret, typename... Args>
Application<_id>& route_api(std::function<Ret(Args...)> func)
{
ApiResponseRegister<_id, name, Ret(Args...)>::func = func;
return *this;
}
template<FixedString name, typename Lambda>
Application<_id>& route_api(Lambda func)
{
return route_api<name>(std::function(func));
}
Application<_id>& route_view(std::string_view name, auto&& func)
{
return *this;
}
};
template<size_t id = unique_id<size_t{}, decltype([] {})>()>
auto CreateApp = Application<id>{};
// ---------- Example Usage ----------
class UserData {
public:
UserData(std::string username) : username(username) {}
std::string getUsername() const { return username; }
private:
std::string username;
};
int main() {
Application<> app;
app
.route_api<"flight">([&]() -> void
{
int x;
std::cin >> x;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "text" << sizeof(app) << std::endl;
std::cout << "text" << x << std::endl;
})
.route_api<"flight">([&]() -> void
{
std::cout << "haha" << std::endl;
})
.route_api<"getUserData">([&](std::string username)
{
return UserData{ username };
})
.route_view("/flight", [&](const ApiResponse<"flight", void()>& flightGetter)
{
std::cout << "text" << sizeof(app) << std::endl;
std::cout << "waiting for API Response" << std::endl;
flightGetter.get_future().wait();
return app.render("index.html", std::vector<std::string>{ "text1", "text2" });
});
const ApiResponse<"flight", void()>& var = *(new ApiResponseRegister<0, "flight", void()>());
var.get_future().wait();
delete& var;
return 0;
}- APIs are generic methods that might or might not accept parameters, do certain operations (business logic) and might or might not respond/return with data
ApiResponseclass is a wrapper for APIs' methods that enables asynchronous call to the API in order to retrieve the wanted data- Views are meant to be platform-specific:
- rendering HTML based on the data when it comes to Web Application
- rendering XAML with ModelView containing the data when it comes to Mobile/Desktop Application (using .NET MAUI)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request