Unverified Commit a345fcc6 authored by Andrey Garaev's avatar Andrey Garaev Committed by GitHub

Implement router static checks (#808)

* feat router: Implement static checks

* Actualize checks
parent f2f5a50f
......@@ -306,29 +306,72 @@ void Head(Router &router, const std::string &resource, Route::Handler handler);
void NotFound(Router &router, Route::Handler handler);
namespace details {
template <class... Args> struct TypeList {
template <size_t N> struct At {
template <typename... Args>
struct TypeList {
template <size_t N>
struct At {
static_assert(N < sizeof...(Args), "Invalid index");
typedef typename std::tuple_element<N, std::tuple<Args...>>::type Type;
using Type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
};
template <typename... Args> void static_checks() {
template <typename Request, typename Response>
struct BindChecks {
constexpr static bool request_check =
std::is_const<typename std::remove_reference<Request>::type>::value &&
std::is_lvalue_reference<typename std::remove_cv<Request>::type>::value &&
std::is_same<typename std::decay<Request>::type, Rest::Request>::value;
constexpr static bool response_check =
!std::is_const<typename std::remove_reference<Response>::type>::value &&
std::is_same<typename std::remove_reference<Response>::type,
Response>::value &&
std::is_same<typename std::decay<Response>::type,
Http::ResponseWriter>::value;
static_assert(
request_check && response_check,
"Function should accept (const Rest::Request&, HttpResponseWriter)");
};
template <typename Request, typename Response>
struct MiddlewareChecks {
constexpr static bool request_check =
!std::is_const<typename std::remove_reference<Request>::type>::value &&
std::is_lvalue_reference<typename std::remove_cv<Request>::type>::value &&
std::is_same<typename std::decay<Request>::type, Http::Request>::value;
constexpr static bool response_check =
!std::is_const<typename std::remove_reference<Response>::type>::value &&
std::is_lvalue_reference<
typename std::remove_cv<Response>::type>::value &&
std::is_same<typename std::decay<Response>::type,
Http::ResponseWriter>::value;
static_assert(request_check && response_check,
"Function should accept (Http::Request&, HttpResponseWriter&)");
};
template <template <typename, typename> class Checks, typename... Args>
constexpr void static_checks() {
static_assert(sizeof...(Args) == 2, "Function should take 2 parameters");
// typedef details::TypeList<Args...> Arguments;
// Disabled now as it
// 1/ does not compile
// 2/ might not be relevant
#if 0
static_assert(std::is_same<Arguments::At<0>::Type, const Rest::Request&>::value, "First argument should be a const Rest::Request&");
static_assert(std::is_same<typename Arguments::At<0>::Type, Http::Response>::value, "Second argument should be a Http::Response");
#endif
using Arguments = details::TypeList<Args...>;
using Request = typename Arguments::template At<0>::Type;
using Response = typename Arguments::template At<1>::Type;
// instantiate template this way
constexpr Checks<Request, Response> checks;
UNUSED(checks);
}
} // namespace details
template <typename Result, typename Cls, typename... Args, typename Obj>
Route::Handler bind(Result (Cls::*func)(Args...), Obj obj) {
details::static_checks<Args...>();
details::static_checks<details::BindChecks, Args...>();
return [=](const Rest::Request &request, Http::ResponseWriter response) {
(obj->*func)(request, std::move(response));
......@@ -339,7 +382,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), Obj obj) {
template <typename Result, typename Cls, typename... Args, typename Obj>
Route::Handler bind(Result (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) {
details::static_checks<Args...>();
details::static_checks<details::BindChecks, Args...>();
return [=](const Rest::Request &request, Http::ResponseWriter response) {
(objPtr.get()->*func)(request, std::move(response));
......@@ -350,7 +393,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) {
template <typename Result, typename... Args>
Route::Handler bind(Result (*func)(Args...)) {
details::static_checks<Args...>();
details::static_checks<details::BindChecks, Args...>();
return [=](const Rest::Request &request, Http::ResponseWriter response) {
func(request, std::move(response));
......@@ -361,29 +404,30 @@ Route::Handler bind(Result (*func)(Args...)) {
template <typename Cls, typename... Args, typename Obj>
Route::Middleware middleware(bool (Cls::*func)(Args...), Obj obj) {
details::static_checks<Args...>();
details::static_checks<details::MiddlewareChecks, Args...>();
return [=](Http::Request &request, Http::ResponseWriter &response) {
return (obj->*func)(request, response);
};
return [=](Http::Request &request, Http::ResponseWriter &response) {
return (obj->*func)(request, response);
};
}
template <typename Cls, typename... Args, typename Obj>
Route::Middleware middleware(bool (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) {
details::static_checks<Args...>();
Route::Middleware middleware(bool (Cls::*func)(Args...),
std::shared_ptr<Obj> objPtr) {
details::static_checks<details::MiddlewareChecks, Args...>();
return [=](Http::Request &request, Http::ResponseWriter &response) {
return (objPtr.get()->*func)(request, response);
};
return [=](Http::Request &request, Http::ResponseWriter &response) {
return (objPtr.get()->*func)(request, response);
};
}
template <typename... Args>
Route::Middleware middleware(bool (*func)(Args...)) {
details::static_checks<Args...>();
details::static_checks<details::MiddlewareChecks, Args...>();
return [=](Http::Request &request, Http::ResponseWriter &response) {
return func(request, response);
};
return [=](Http::Request &request, Http::ResponseWriter &response) {
return func(request, response);
};
}
} // namespace Routes
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment