include/ylt/coro_rpc/impl/rpc_execute.hpp (198 lines of code) (raw):

/* * Copyright (c) 2023, Alibaba Group Holding Limited; * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <functional> #include <memory> #include <optional> #include <string> #include <string_view> #include <type_traits> #include <variant> #include "context.hpp" #include "coro_connection.hpp" #include "ylt/coro_rpc/impl/errno.h" #include "ylt/easylog.hpp" #include "ylt/util/type_traits.h" namespace coro_rpc::internal { // TODO: remove this later template <bool is_conn, typename First> auto get_return_type() { if constexpr (is_conn) { using T = typename First::return_type; if constexpr (std::is_void_v<T>) { return; } else { return T{}; } } else { return First{}; } } template <typename rpc_protocol> using rpc_context = std::shared_ptr<context_info_t<rpc_protocol>>; using rpc_conn = std::shared_ptr<coro_connection>; template <typename rpc_protocol, typename serialize_proto, auto func, typename Self = void> inline std::pair<coro_rpc::err_code, std::string> execute( std::string_view data, rpc_context<rpc_protocol> &context_info, Self *self = nullptr) { using namespace std::string_literals; using T = decltype(func); using param_type = util::function_parameters_t<T>; using return_type = util::function_return_type_t<T>; if constexpr (!std::is_void_v<param_type>) { using First = std::tuple_element_t<0, param_type>; constexpr bool is_conn = requires { typename First::return_type; }; if constexpr (is_conn) { static_assert(std::is_void_v<return_type>, "The return_type must be void"); } using conn_return_type = decltype(get_return_type<is_conn, First>()); constexpr bool has_coro_conn_v = std::is_convertible_v<context_base<conn_return_type, rpc_protocol>, First>; auto args = util::get_args<has_coro_conn_v, param_type>(); bool is_ok = true; constexpr size_t size = std::tuple_size_v<decltype(args)>; if constexpr (size > 0) { is_ok = serialize_proto::deserialize_to(args, data); } if (!is_ok) AS_UNLIKELY { return std::pair{err_code{errc::invalid_rpc_arguments}, "invalid rpc arg"s}; } if constexpr (std::is_void_v<return_type>) { if constexpr (std::is_void_v<Self>) { if constexpr (has_coro_conn_v) { // call void func(coro_conn, args...) std::apply(func, std::tuple_cat( std::forward_as_tuple( context_base<conn_return_type, rpc_protocol>( context_info)), std::move(args))); } else { // call void func(args...) std::apply(func, std::move(args)); } } else { if constexpr (has_coro_conn_v) { // call void self->func(coro_conn, args...) std::apply( func, std::tuple_cat( std::forward_as_tuple( *self, context_base<conn_return_type, rpc_protocol>( context_info)), std::move(args))); } else { // call void self->func(args...) std::apply(func, std::tuple_cat(std::forward_as_tuple(*self), std::move(args))); } } return std::pair{err_code{}, serialize_proto::serialize()}; } else { if constexpr (std::is_void_v<Self>) { // call return_type func(args...) return std::pair{err_code{}, serialize_proto::serialize( std::apply(func, std::move(args)))}; } else { // call return_type self->func(args...) return std::pair{err_code{}, serialize_proto::serialize(std::apply( func, std::tuple_cat(std::forward_as_tuple(*self), std::move(args))))}; } } } else { if constexpr (std::is_void_v<return_type>) { if constexpr (std::is_void_v<Self>) { func(); } else { (self->*func)(); } return std::pair{err_code{}, serialize_proto::serialize()}; } else { if constexpr (std::is_void_v<Self>) { return std::pair{err_code{}, serialize_proto::serialize(func())}; } else { return std::pair{err_code{}, serialize_proto::serialize((self->*func)())}; } } } } template <typename rpc_protocol, typename serialize_proto, auto func, typename Self = void> inline async_simple::coro::Lazy<std::pair<coro_rpc::err_code, std::string>> execute_coro(std::string_view data, Self *self = nullptr) { using namespace std::string_literals; using T = decltype(func); using param_type = util::function_parameters_t<T>; using return_type = typename get_type_t< typename util::function_return_type_t<T>::ValueType>::type; if constexpr (!std::is_void_v<param_type>) { using First = std::tuple_element_t<0, param_type>; constexpr bool is_conn = requires { typename First::return_type; }; static_assert( !is_conn, "context<T> is not allowed as parameter in coroutine function"); bool is_ok = true; constexpr size_t size = std::tuple_size_v<param_type>; param_type args; if constexpr (size > 0) { is_ok = serialize_proto::deserialize_to(args, data); } if (!is_ok) AS_UNLIKELY { co_return std::make_pair(coro_rpc::errc::invalid_rpc_arguments, "invalid rpc function arguments"s); } if constexpr (std::is_void_v<return_type>) { if constexpr (std::is_void_v<Self>) { // call void func(args...) co_await std::apply(func, std::move(args)); } else { // call void self->func(args...) co_await std::apply(func, std::tuple_cat(std::forward_as_tuple(*self), std::move(args))); } co_return std::pair{err_code{}, serialize_proto::serialize()}; } else { if constexpr (std::is_void_v<Self>) { // call return_type func(args...) co_return std::pair{err_code{}, serialize_proto::serialize( co_await std::apply(func, std::move(args)))}; } else { // call return_type self->func(args...) co_return std::pair{ err_code{}, serialize_proto::serialize(co_await std::apply( func, std::tuple_cat(std::forward_as_tuple(*self), std::move(args))))}; } } } else { if constexpr (std::is_void_v<return_type>) { if constexpr (std::is_void_v<Self>) { co_await func(); } else { // clang-format off co_await (self->*func)(); // clang-format on } co_return std::pair{err_code{}, serialize_proto::serialize()}; } else { if constexpr (std::is_void_v<Self>) { co_return std::pair{err_code{}, serialize_proto::serialize(co_await func())}; } else { // clang-format off co_return std::pair{err_code{},serialize_proto::serialize(co_await (self->*func)())}; // clang-format on } } } } } // namespace coro_rpc::internal