summaryrefslogtreecommitdiff
path: root/modules/codec/c++/interface.hpp
blob: e1c9a12eb7b797a8a98c920b89e314975122517c (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
128
129
130
131
132
133
134
135
136
137
138
139
#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 DataSchema, typename Encode, typename Storage>
struct FuncReturnTypeHelper {
	using Type = data<DataSchema,Encode,Storage>;
};

template<typename Encode, typename Storage>
struct FuncReturnTypeHelper<schema::Void, Encode, Storage> {
	using Type = void;
};

template<typename Request, typename Response, typename Encode, typename Storage, typename Ctx>
struct FuncTypeHelper {
	using Type = std::function<error_or<typename FuncReturnTypeHelper<Response,Encode,Storage>::Type>(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<error_or<typename FuncReturnTypeHelper<Response, Encode, Storage>::Type>(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_;
	using ResponseDataType = typename impl::FuncReturnTypeHelper<Response, Encode, Storage>::Type;
public:
	template<typename Func>
		function(Func func):
				func_{std::move(func)}
		{}

		error_or<ResponseDataType> 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<
			typename impl::FuncReturnTypeHelper<
				typename parameter_pack_type<
						parameter_key_pack_index<
								Lit, Names...
						>::value
				, Responses...>::type
		, Encode, Storage>::Type > 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)...};
		}
};
}