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); ...@@ -306,29 +306,72 @@ void Head(Router &router, const std::string &resource, Route::Handler handler);
void NotFound(Router &router, Route::Handler handler); void NotFound(Router &router, Route::Handler handler);
namespace details { namespace details {
template <class... Args> struct TypeList { template <typename... Args>
template <size_t N> struct At { struct TypeList {
template <size_t N>
struct At {
static_assert(N < sizeof...(Args), "Invalid index"); 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"); static_assert(sizeof...(Args) == 2, "Function should take 2 parameters");
// typedef details::TypeList<Args...> Arguments;
// Disabled now as it using Arguments = details::TypeList<Args...>;
// 1/ does not compile
// 2/ might not be relevant using Request = typename Arguments::template At<0>::Type;
#if 0 using Response = typename Arguments::template At<1>::Type;
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"); // instantiate template this way
#endif constexpr Checks<Request, Response> checks;
UNUSED(checks);
} }
} // namespace details } // namespace details
template <typename Result, typename Cls, typename... Args, typename Obj> template <typename Result, typename Cls, typename... Args, typename Obj>
Route::Handler bind(Result (Cls::*func)(Args...), Obj 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) { return [=](const Rest::Request &request, Http::ResponseWriter response) {
(obj->*func)(request, std::move(response)); (obj->*func)(request, std::move(response));
...@@ -339,7 +382,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), Obj obj) { ...@@ -339,7 +382,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), Obj obj) {
template <typename Result, typename Cls, typename... Args, typename Obj> template <typename Result, typename Cls, typename... Args, typename Obj>
Route::Handler bind(Result (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) { 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) { return [=](const Rest::Request &request, Http::ResponseWriter response) {
(objPtr.get()->*func)(request, std::move(response)); (objPtr.get()->*func)(request, std::move(response));
...@@ -350,7 +393,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) { ...@@ -350,7 +393,7 @@ Route::Handler bind(Result (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) {
template <typename Result, typename... Args> template <typename Result, typename... Args>
Route::Handler bind(Result (*func)(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) { return [=](const Rest::Request &request, Http::ResponseWriter response) {
func(request, std::move(response)); func(request, std::move(response));
...@@ -361,29 +404,30 @@ Route::Handler bind(Result (*func)(Args...)) { ...@@ -361,29 +404,30 @@ Route::Handler bind(Result (*func)(Args...)) {
template <typename Cls, typename... Args, typename Obj> template <typename Cls, typename... Args, typename Obj>
Route::Middleware middleware(bool (Cls::*func)(Args...), Obj 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 [=](Http::Request &request, Http::ResponseWriter &response) {
return (obj->*func)(request, response); return (obj->*func)(request, response);
}; };
} }
template <typename Cls, typename... Args, typename Obj> template <typename Cls, typename... Args, typename Obj>
Route::Middleware middleware(bool (Cls::*func)(Args...), std::shared_ptr<Obj> objPtr) { Route::Middleware middleware(bool (Cls::*func)(Args...),
details::static_checks<Args...>(); std::shared_ptr<Obj> objPtr) {
details::static_checks<details::MiddlewareChecks, Args...>();
return [=](Http::Request &request, Http::ResponseWriter &response) { return [=](Http::Request &request, Http::ResponseWriter &response) {
return (objPtr.get()->*func)(request, response); return (objPtr.get()->*func)(request, response);
}; };
} }
template <typename... Args> template <typename... Args>
Route::Middleware middleware(bool (*func)(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 [=](Http::Request &request, Http::ResponseWriter &response) {
return func(request, response); return func(request, response);
}; };
} }
} // namespace Routes } // 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