aboutsummaryrefslogblamecommitdiffstats
path: root/routing.h
blob: a150a4e7e8472db02829d9d165b2e587eac5ed78 (plain) (tree)
1
2
3
4
5
6


                  


                  






                         
                                                                                
         







                                                       

         
                                                 



                                                 






                                                     



                                                 







































































                                                                                                                         




                





                                                                  
         
                                                         
         

                                    

      
#pragma once

#include <cstdint>
#include <utility>
#include <string>
#include <tuple>

#include "utility.h"

namespace flask
{
    namespace black_magic
    {
        constexpr bool is_equ_n(const_str a, int ai, const_str b, int bi, int n)
        {
            return 
                ai + n > a.size() || bi + n > b.size() 
                    ? false :
                n == 0 
                    ? true : 
                a[ai] != b[bi] 
                    ? false : 
                is_equ_n(a,ai+1,b,bi+1,n-1);
        }

        constexpr bool is_int(const_str s, int i)
        {
            return is_equ_n(s, i, "<int>", 0, 5);
        }

        constexpr bool is_float(const_str s, int i)
        {
            return is_equ_n(s, i, "<float>", 0, 7) ||
                is_equ_n(s, i, "<double>", 0, 8);
        }

        constexpr bool is_str(const_str s, int i)
        {
            return is_equ_n(s, i, "<str>", 0, 5);
        }

        constexpr bool is_path(const_str s, int i)
        {
            return is_equ_n(s, i, "<path>", 0, 6);
        }

        template <typename ...Args>
        struct Caller
        {
            template <typename F>
            void operator()(F f, Args... args)
            {
                f(args...);
            }
        };


        template <int N, typename ... Args> struct S;
        template <int N, typename Arg, typename ... Args> struct S<N, Arg, Args...> {
            static_assert(N <= 4+1, "too many routing arguments (maximum 5)");
            template <typename T>
            using push = typename std::conditional<(N>4), S<N, Arg, Args...>, S<N+1, Arg, Args..., T>>::type;
            using pop = S<N-1, Args...>;
        };
        template <> struct S<0>
        {
            template <typename T>
            using push = S<1, T>;
        };

        template <typename F, typename Set>
        struct CallHelper;
        template <typename F, int N, typename ...Args>
        struct CallHelper<F, S<N, Args...>>
        {
            template <typename F1, typename ...Args1, typename = 
                decltype(std::declval<F1>()(std::declval<Args1>()...))
                >
            static char __test(int);

            template <typename ...>
            static int __test(...);

            static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
        };

        static_assert(CallHelper<void(), S<0>>::value, "");
        static_assert(CallHelper<void(int), S<1, int>>::value, "");
        static_assert(!CallHelper<void(int), S<0>>::value, "");
        static_assert(!CallHelper<void(int), S<2, int, int>>::value, "");

        template <typename F, 
            typename Set = S<0>>
        constexpr bool validate_helper(const_str rule, unsigned i=0)
        {
            return 
                i == rule.size() 
                    ? CallHelper<F, Set>::value :
                is_int(rule, i)
                    ? validate_helper<F, typename Set::template push<int>>(rule, find_closing_tag(rule, i+1)+1) :
                is_float(rule, i)
                    ? validate_helper<F, typename Set::template push<double>>(rule, find_closing_tag(rule, i+1)+1) :
                is_str(rule, i)
                    ? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
                is_path(rule, i)
                    ? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
                validate_helper<F, Set>(rule, i+1)
            ;
        }

        static_assert(validate_helper<void()>("/"),"");
        static_assert(validate_helper<void(int)>("/<int>"),"");
        static_assert(!validate_helper<void()>("/<int>"),"");
    }

    class Router
    {
    public:
        constexpr Router(black_magic::const_str rule) : rule(rule)
        {
        }

        template <typename F>
        constexpr bool validate() const
        {
            return black_magic::validate_helper<F>(rule);
        }
    private:
        black_magic::const_str rule;
    };
}