5 #ifndef PACKIO_DISPATCHER_H
6 #define PACKIO_DISPATCHER_H
15 #include <string_view>
19 #include "internal/config.h"
20 #include "internal/movable_function.h"
21 #include "internal/rpc.h"
22 #include "internal/utils.h"
31 template <
typename Rpc,
template <
class...>
class Map = default_map,
typename Lockable = default_mutex>
39 using args_type = decltype(
typename rpc_type::request_type{}.args);
51 typename SyncProcedure,
52 std::size_t N = internal::func_traits<SyncProcedure>::args_count>
54 std::string_view name,
55 const std::array<std::string, N>& arguments_names,
58 PACKIO_STATIC_ASSERT_TRAIT(SyncProcedure);
59 std::unique_lock lock{map_mutex_};
63 std::make_shared<function_type>(wrap_sync(
64 std::forward<SyncProcedure>(fct), arguments_names)))
69 template <
typename SyncProcedure>
70 bool add(std::string_view name, SyncProcedure&& fct)
72 return add<SyncProcedure, 0>(name, {}, std::forward<SyncProcedure>(fct));
80 typename AsyncProcedure,
81 std::size_t N = internal::func_traits<AsyncProcedure>::args_count - 1>
83 std::string_view name,
84 const std::array<std::string, N>& arguments_names,
87 PACKIO_STATIC_ASSERT_TTRAIT(AsyncProcedure,
rpc_type);
88 std::unique_lock lock{map_mutex_};
92 std::make_shared<function_type>(wrap_async(
93 std::forward<AsyncProcedure>(fct), arguments_names)))
98 template <
typename AsyncProcedure>
99 bool add_async(std::string_view name, AsyncProcedure&& fct)
101 return add_async<AsyncProcedure, 0>(
102 name, {}, std::forward<AsyncProcedure>(fct));
105 #if defined(PACKIO_HAS_CO_AWAIT)
113 typename CoroProcedure,
114 std::size_t N = internal::func_traits<CoroProcedure>::args_count>
116 std::string_view name,
117 const Executor& executor,
118 const std::array<std::string, N>& arguments_names,
119 CoroProcedure&& coro)
121 PACKIO_STATIC_ASSERT_TRAIT(CoroProcedure);
122 std::unique_lock lock{map_mutex_};
126 std::make_shared<function_type>(wrap_coro(
127 executor, std::forward<CoroProcedure>(coro), arguments_names)))
132 template <
typename Executor,
typename CoroProcedure>
133 bool add_coro(std::string_view name,
const Executor& executor, CoroProcedure&& coro)
135 return add_coro<Executor, CoroProcedure, 0>(
136 name, executor, {}, std::forward<CoroProcedure>(coro));
141 typename ExecutionContext,
142 typename CoroProcedure,
143 std::size_t N = internal::func_traits<CoroProcedure>::args_count>
145 std::string_view name,
146 ExecutionContext& ctx,
147 const std::array<std::string, N>& arguments_names,
148 CoroProcedure&& coro)
150 return add_coro<decltype(ctx.get_executor()), CoroProcedure, N>(
154 std::forward<CoroProcedure>(coro));
158 template <
typename ExecutionContext,
typename CoroProcedure>
159 bool add_coro(std::string_view name, ExecutionContext& ctx, CoroProcedure&& coro)
161 return add_coro<ExecutionContext, CoroProcedure, 0>(
162 name, ctx, {}, std::forward<CoroProcedure>(coro));
164 #endif // defined(PACKIO_HAS_CO_AWAIT)
171 std::unique_lock lock{map_mutex_};
172 return function_map_.erase(name);
178 bool has(
const std::string& name)
const
180 std::unique_lock lock{map_mutex_};
181 return function_map_.find(name) != function_map_.end();
188 std::unique_lock lock{map_mutex_};
189 size_t size = function_map_.size();
190 function_map_.clear();
196 std::vector<std::string>
known()
const
198 std::unique_lock lock{map_mutex_};
199 std::vector<std::string> names;
200 names.reserve(function_map_.size());
202 function_map_.begin(),
204 std::back_inserter(names),
205 [](
const typename decltype(function_map_)::value_type& pair) {
213 std::unique_lock lock{map_mutex_};
214 auto it = function_map_.find(name);
215 if (it == function_map_.end()) {
224 using function_map_type = Map<std::string, function_ptr_type>;
226 template <
typename TArgs, std::
size_t NNamedArgs>
227 static void static_assert_arguments_name_and_count()
230 NNamedArgs == 0 || std::tuple_size_v<TArgs> == NNamedArgs,
231 "incompatible arguments count and names");
234 template <
typename F, std::
size_t N>
235 auto wrap_sync(F&& fct,
const std::array<std::string, N>& args_names)
238 internal::decay_tuple_t<typename internal::func_traits<F>::args_type>;
239 using result_type =
typename internal::func_traits<F>::result_type;
240 static_assert_arguments_name_and_count<value_args, N>();
243 [fct = std::forward<F>(fct), args_names](
244 completion_handler<rpc_type> handler,
args_type&& args)
mutable {
245 auto typed_args = rpc_type::template extract_args<value_args>(
246 std::move(args), args_names);
248 PACKIO_DEBUG(
"incompatible arguments");
249 handler.set_error(
"Incompatible arguments");
253 if constexpr (std::is_void_v<result_type>) {
254 std::apply(fct, std::move(*typed_args));
258 handler(std::apply(fct, std::move(*typed_args)));
263 template <
typename F, std::
size_t N>
264 auto wrap_async(F&& fct,
const std::array<std::string, N>& args_names)
266 using args =
typename internal::func_traits<F>::args_type;
267 using value_args = internal::decay_tuple_t<internal::shift_tuple_t<args>>;
268 static_assert_arguments_name_and_count<value_args, N>();
271 [fct = std::forward<F>(fct), args_names](
272 completion_handler<rpc_type> handler,
args_type&& args)
mutable {
273 auto typed_args = rpc_type::template extract_args<value_args>(
274 std::move(args), args_names);
276 PACKIO_DEBUG(
"incompatible arguments");
277 handler.set_error(
"Incompatible arguments");
282 [&](
auto&&... args) {
283 fct(std::move(handler),
284 std::forward<decltype(args)>(args)...);
286 std::move(*typed_args));
290 #if defined(PACKIO_HAS_CO_AWAIT)
291 template <
typename E,
typename C, std::
size_t N>
295 const std::array<std::string, N>& args_names)
298 internal::decay_tuple_t<typename internal::func_traits<C>::args_type>;
300 typename internal::func_traits<C>::result_type::value_type;
301 static_assert_arguments_name_and_count<value_args, N>();
303 return [executor, coro = std::forward<C>(coro), args_names](
304 completion_handler<rpc_type> handler,
306 auto typed_args = rpc_type::template extract_args<value_args>(
307 std::move(args), args_names);
309 PACKIO_DEBUG(
"incompatible arguments");
310 handler.set_error(
"Incompatible arguments");
316 [typed_args = std::move(*typed_args),
317 handler = std::move(handler),
318 coro = std::forward<C>(coro)]()
mutable -> net::awaitable<void> {
319 if constexpr (std::is_void_v<result_type>) {
320 co_await std::apply(coro, std::move(typed_args));
324 handler(co_await std::apply(coro, std::move(typed_args)));
327 [](std::exception_ptr exc) {
329 std::rethrow_exception(exc);
334 #endif // defined(PACKIO_HAS_CO_AWAIT)
337 function_map_type function_map_;
342 #endif // PACKIO_DISPATCHER_H