summaryrefslogtreecommitdiff
path: root/modules/codec/c++/interface.hpp
blob: 0f41f554ee59ad9b96b0a59d6608d9eaac143c8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once

#include <functional>

#include <forstio/error.hpp>

#include "schema.hpp"
#include "data.hpp"

namespace saw {
template<typename SchemaFunc, typename Encode, typename Storage, typename Context = void_t >
class function;

namespace impl {
template<typename Request, typename Response, typename Encode, typename Storage, typename Ctx>
struct FuncTypeHelper {
	using Type = std::function<data<Response, Encode, Storage>(data<Request, Encode, Storage>&, Ctx)>;
};

template<typename Request, typename Response, typename Encode, typename Storage>
struct FuncTypeHelper<Request, Response, Encode, Storage, void_t> {
	using Type = std::function<data<Response, Encode, Storage>(data<Request, Encode, Storage>&)>;
};
}

template<typename Request, typename Response, typename Encode, typename Storage, typename Context>
class function<schema::Function<Request, Response>, Encode, Storage, Context> {
private:
	typename impl::FuncTypeHelper<Request, Response, Encode, Storage, Context>::Type func_;
public:
	template<typename Func>
		function(Func func):
				func_{std::move(func)}
		{}

		error_or<data<Response, Encode, Storage>> call(data<Request, Encode, Storage>& req, Context ctx = {}){
			if constexpr (std::is_same_v<Context, void_t>){
				(void) ctx;
				return func_(req);
			} else {
				return func_(req, ctx);
			}
		}
};

template<typename T, typename Encode, typename Storage = storage::Default, typename Context = void_t >
class interface;

template<typename... Requests, typename... Responses, string_literal... Names, typename Encode, typename Storage, typename Context>
class interface<schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>, Encode, Storage, Context> {
public:
	using Schema = schema::Interface<schema::Member<schema::Function<Requests, Responses>,Names>...>;
private:
		std::tuple<function<schema::Function<Requests, Responses>, Encode, Storage, Context>...> funcs_;
public:
		interface(function<schema::Function<Requests, Responses>, Encode, Storage, Context>... funcs):
				funcs_{std::move(funcs)...}
		{}

		/**
		 * Get the function based on the string literal matching the position in the tuple
		 */
		template<string_literal Lit>
		function<
				schema::Function<
						typename parameter_pack_type<
								parameter_key_pack_index<
										Lit, Names...
								>::value
						, Requests...>::type
				,
						typename parameter_pack_type<
								parameter_key_pack_index<
										Lit, Names...
								>::value
						, Responses...>::type
				>
		,		Encode
		,		Storage
		,		Context
		>& get(){
				return std::get<parameter_key_pack_index<Lit, Names...>::value>(funcs_);
		}

		template<string_literal Lit>
		error_or<
			data<
				typename parameter_pack_type<
						parameter_key_pack_index<
								Lit, Names...
						>::value
				, Responses...>::type
		, Encode, Storage>> call(
						data<
								typename parameter_pack_type<
										parameter_key_pack_index<
												Lit, Names...
										>::value
								, Requests...>::type
						, Encode, Storage>& req,
						Context ctx = {}
				){
				if constexpr (std::is_same_v<Context, void_t>) {
					(void) ctx;
					return get<Lit>().call(req);
				}else{
					return get<Lit>().call(req, ctx);
				}
		}
};

template<typename T, typename Encode, typename Storage = storage::Default, typename Context = void_t>
struct function_factory {
		template<typename Func>
		static function<T,Encode, Storage, Context> create(Func func){
				return function<T,Encode, Storage, Context> {std::move(func)};
		}
};

template<typename T, typename Encode, typename Storage = storage::Default, typename Context = void_t>
struct interface_factory {
		template<typename... Func>
		static interface<T,Encode,Storage,Context> create(Func... func){
				return interface<T,Encode,Storage,Context>{std::move(func)...};
		}
};
}