From 8b539caf6930b7e017b08c787766608586513921 Mon Sep 17 00:00:00 2001 From: Jackson Date: Fri, 19 Mar 2021 13:25:00 -0400 Subject: [PATCH] Bugfixes (#56) * Performance, usability, and consistency improvements: * Streamlined by using tuple everywhere * Previously, `std::array` was used * Removed some redundant code, refactored to be more efficient * Added error detection via err_mesg string and exceptions --- CMakeLists.txt | 15 +- include/rpc.hpp | 574 ++++++++---------------- include/rpc_adapters/rpc_boost_json.hpp | 85 ++-- include/rpc_adapters/rpc_njson.hpp | 126 ++++-- include/rpc_adapters/rpc_rapidjson.hpp | 116 +++-- include/rpc_dispatch_helper.hpp | 2 +- meson.build | 2 +- tests/rpc.benchmark.cpp | 243 +++++----- tests/rpc.client.hpp | 2 +- tests/rpc.server.cpp | 24 +- tests/rpc.test.cpp | 107 +++-- tests/test_structs.hpp | 2 +- 12 files changed, 650 insertions(+), 648 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16ddcb1f..2c265174 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1...3.19) project( "rpc.hpp" - VERSION 0.3.2 + VERSION 0.3.3 DESCRIPTION "Simple RPC Header-Only Library" LANGUAGES CXX) @@ -65,9 +65,16 @@ if(CXX_MSVC) /w14906 /w14928 /we4834 - /bigobj) - set(MIN_WARNING /W1 /experimental:external /external:W0 - /external:anglebrackets /wd4619 /bigobj) + /bigobj + -D_WIN32_WINNT=0x0A00) + set(MIN_WARNING + /W1 + /experimental:external + /external:W0 + /external:anglebrackets + /wd4619 + /bigobj + -D_WIN32_WINNT=0x0A00) elseif(CXX_GCC OR CXX_MINGW) set(FULL_WARNING -Wall diff --git a/include/rpc.hpp b/include/rpc.hpp index a4b11d21..165b33de 100644 --- a/include/rpc.hpp +++ b/include/rpc.hpp @@ -1,7 +1,7 @@ ///@file rpc.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Header-only library for serialized RPC usage -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -535,221 +535,143 @@ namespace details size_t m_size{ 0 }; T* m_ptr; }; -} // namespace rpc::details - -///@brief Polymorphic base class for \ref packed_func -class packed_func_base -{ -public: - virtual ~packed_func_base() = default; - - ///@brief Construct a new packed_func_base object - /// - ///@param func_name Name of the function (case-sensitive) - explicit packed_func_base(std::string func_name) : m_func_name(std::move(func_name)) {} - - // Prevents slicing - packed_func_base& operator=(const packed_func_base&) = delete; - packed_func_base& operator=(packed_func_base&&) = delete; - - ///@brief Get the function name - /// - ///@return std::string Name of the stored function (case-sensitive) - [[nodiscard]] std::string get_func_name() const noexcept { return m_func_name; } - - ///@brief Get the error message - /// - ///@return std::string The error message (if any) - [[nodiscard]] std::string get_err_mesg() const noexcept { return m_err_mesg; } - - ///@brief Set the error message - /// - ///@param mesg String to set as the error message - void set_err_mesg(const std::string& mesg) & noexcept { m_err_mesg = mesg; } - -protected: - packed_func_base(const packed_func_base&) = default; - packed_func_base(packed_func_base&&) noexcept = default; -private: - std::string m_func_name; - std::string m_err_mesg{}; -}; + ///@brief Polymorphic base class for \ref packed_func + template + class packed_func_base + { + public: + using args_type = std::tuple>...>; -///@brief Class reprensenting a function call including its name, result, and parameters -/// -///@tparam R The return type -///@tparam Args The list of parameter type(s) -template -class packed_func final : public packed_func_base -{ -public: - ///@brief The type of the packed_func's result - using result_type = R; + virtual ~packed_func_base() = default; - ///@brief Construct a new packed_func object - /// - ///@param func_name Name of the function (case-sensitive) - ///@param result Function call result (if no result yet, use std::nullopt) - ///@param args List of parameters for the function call - packed_func(std::string func_name, std::optional result, - std::array args) - : packed_func_base(std::move(func_name)), m_result(std::move(result)), - m_args(std::move(args)) - { - } + packed_func_base(std::string func_name, args_type args) + : m_func_name(std::move(func_name)), m_args(std::move(args)) + { + } - packed_func(const packed_func&) = default; - packed_func(packed_func&&) noexcept = default; - packed_func& operator=(const packed_func&) & = default; - packed_func& operator=(packed_func&&) & = default; + // Prevents slicing + packed_func_base& operator=(const packed_func_base&) = delete; + packed_func_base& operator=(packed_func_base&&) = delete; - explicit operator bool() const noexcept { return m_result.has_value(); } + [[nodiscard]] std::string& get_func_name() & noexcept { return m_func_name; } + [[nodiscard]] const std::string& get_func_name() const& noexcept { return m_func_name; } + [[nodiscard]] std::string get_func_name() && noexcept { return std::move(m_func_name); } - ///@brief Get the result of the function call (if it exists) - /// - ///@return std::optional If the function has not been called, or resulted in a err0r: std::nullopt, else: the result of the function call - [[nodiscard]] std::optional get_result() const noexcept { return m_result; } + [[nodiscard]] std::string& get_err_mesg() & noexcept { return m_err_mesg; } + [[nodiscard]] const std::string& get_err_mesg() const& noexcept { return m_err_mesg; } + [[nodiscard]] std::string get_err_mesg() && noexcept { return std::move(m_err_mesg); } - ///@brief Set the result - /// - ///@param value Value of type R to set as the result - void set_result(R value) & noexcept { m_result = std::move(value); } + void set_err_mesg(const std::string& mesg) & noexcept { m_err_mesg = mesg; } + void set_err_mesg(std::string&& mesg) & noexcept { m_err_mesg = std::move(mesg); } - ///@brief Sets the result back to null - void clear_result() & noexcept { m_result = std::nullopt; } + explicit virtual operator bool() const noexcept { return true; } - ///@brief Set a particular argument - /// - ///@tparam T Type of the argument to be set - ///@param arg_index The index (0 start) of the argument to change - ///@param value The value to set the argument to - template - void set_arg(size_t arg_index, const T& value) & - { - if (arg_index > m_args.size()) - { - throw std::logic_error("Index out of bounds for argument list: " - + std::to_string(arg_index) + " > " + std::to_string(m_args.size()) + "!"); - } + [[nodiscard]] args_type& get_args() & noexcept { return m_args; } + [[nodiscard]] const args_type& get_args() const& noexcept { return m_args; } + [[nodiscard]] args_type get_args() && noexcept { return std::move(m_args); } - if (m_args[arg_index].type() != typeid(T)) + template + T& get_arg() & { - const std::string t_name = typeid(T).name(); - throw std::runtime_error("Invalid argument type: \"" + t_name + "\" provided!"); + return std::get(m_args); } - m_args[arg_index] = value; - } - - ///@brief Set a particular argument - /// - ///@tparam T Type of the argument to be set - ///@param arg_index The index (0 start) of the argument to change - ///@param value The value to set the argument to - template - void set_arg(size_t arg_index, T&& value) & - { - if (arg_index > m_args.size()) + template + const T& get_arg() const& { - throw std::logic_error("Index out of bounds for argument list: " - + std::to_string(arg_index) + " > " + std::to_string(m_args.size()) + "!"); + return std::get(m_args); } - if (m_args[arg_index].type() != typeid(T)) + template + T get_arg() && { - const std::string t_name = typeid(T).name(); - throw std::runtime_error("Invalid argument type: \"" + t_name + "\" provided!"); + return std::move(std::get(m_args)); } - m_args[arg_index] = std::move(value); - } - - ///@brief Set all arguments - /// - ///@param args A tuple containing the list of arguments to set - void set_args(const std::tuple>...>& args) & - { - size_t i = 0; - details::for_each_tuple(args, [&i, this](auto x) { m_args[i++] = x; }); - } + ///@brief Set all arguments + /// + ///@param args A tuple containing the list of arguments to set + void set_args(args_type&& args) & { m_args = std::move(args); } - ///@brief Get the arg object - /// - ///@tparam T Type to be acquired from the argument list (via std::any_cast) - ///@param arg_index The index (0 start) of the argument to retrieve - ///@return std::remove_cv_t> The argument's value - template - [[nodiscard]] std::remove_cv_t> get_arg(size_t arg_index) const - { - // TODO: Remove the remove_cv/remove_reference? - return std::any_cast>>(m_args[arg_index]); - } + protected: + packed_func_base(const packed_func_base&) = default; + packed_func_base(packed_func_base&&) noexcept = default; -private: - std::optional m_result{ std::nullopt }; - std::array m_args; + private: + std::string m_func_name; + std::string m_err_mesg{}; + args_type m_args; #if defined(RPC_HPP_ENABLE_POINTERS) - std::array m_arg_sz_arr{}; + std::array m_arg_sz_arr{}; - template - void update_arg_arr_helper( - [[maybe_unused]] std::array&& arg_arr, size_t& count) & - { - if constexpr (std::is_pointer_v) + template + void update_arg_arr_helper( + [[maybe_unused]] std::array&& arg_arr, size_t& count) & { - const auto& arr = std::any_cast< - const details::dyn_array>>&>( - std::move(arg_arr[count])); + if constexpr (std::is_pointer_v) + { + const auto& arr = std::any_cast< + const details::dyn_array>>&>( + std::move(arg_arr[count])); - m_arg_sz_arr[count] = arr.capacity(); - } + m_arg_sz_arr[count] = arr.capacity(); + } - ++count; - } + ++count; + } -public: - ///@brief Get the indexed argument size - /// - ///@param index The index to get the arg size for - ///@return size_t The size (number of elements) for the given argument - [[nodiscard]] size_t get_arg_arr_sz(const size_t index) const { return m_arg_sz_arr[index]; } + public: + ///@brief Get the indexed argument size + /// + ///@param index The index to get the arg size for + ///@return size_t The size (number of elements) for the given argument + [[nodiscard]] size_t get_arg_arr_sz(const size_t index) const + { + return m_arg_sz_arr[index]; + } - ///@brief Set the size for the indexed argument - /// - ///@param index The index to set the arg size for - ///@param sz The size (number of elements) for the given argument - void set_arg_arr_sz(const size_t index, const size_t sz) & { m_arg_sz_arr[index] = sz; } + ///@brief Set the size for the indexed argument + /// + ///@param index The index to set the arg size for + ///@param sz The size (number of elements) for the given argument + void set_arg_arr_sz(const size_t index, const size_t sz) & { m_arg_sz_arr[index] = sz; } - ///@brief Update the argument size array - /// - ///@param arg_arr Array of arguments to reference - void update_arg_arr(std::array arg_arr) & - { - size_t count = 0; - using expander = int[]; - (void)expander{ 0, ((void)update_arg_arr_helper(std::move(arg_arr), count), 0)... }; - } + ///@brief Update the argument size array + /// + ///@param arg_arr Array of arguments to reference + void update_arg_arr(std::array arg_arr) & + { + size_t count = 0; + using expander = int[]; + (void)expander{ 0, + ((void)update_arg_arr_helper(std::move(arg_arr), count), 0)... }; + } #endif -}; + }; +} // namespace rpc::details -///@brief Class reprensenting a function call (with void result) including its name and parameters +///@brief Class reprensenting a function call including its name, result, and parameters /// +///@tparam R The return type ///@tparam Args The list of parameter type(s) -template -class packed_func final : public packed_func_base +template +class packed_func final : public details::packed_func_base { public: - ///@brief The type of the result (void) - using result_type = void; + ///@brief The type of the packed_func's result + using result_type = R; + using typename details::packed_func_base::args_type; ///@brief Construct a new packed_func object /// ///@param func_name Name of the function (case-sensitive) + ///@param result Function call result (if no result yet, use std::nullopt) ///@param args List of parameters for the function call - packed_func(std::string func_name, std::array args) - : packed_func_base(std::move(func_name)), m_args(std::move(args)) + packed_func(std::string func_name, std::optional result, args_type args) + : details::packed_func_base(std::move(func_name), std::move(args)), + m_result(std::move(result)) { } @@ -758,108 +680,49 @@ class packed_func final : public packed_func_base packed_func& operator=(const packed_func&) & = default; packed_func& operator=(packed_func&&) & = default; - explicit operator bool() const noexcept { return true; } - - ///@brief Set a particular argument - /// - ///@tparam T Type of the argument to be set - ///@param arg_index The index (0 start) of the argument to change - ///@param value The value to set the argument to - template - void set_arg(size_t arg_index, const T& value) & - { - if (m_args[arg_index].type() != typeid(T)) - { - const std::string t_name = typeid(T).name(); - throw std::runtime_error("Invalid argument type: \"" + t_name + "\" provided!"); - } - - m_args[arg_index] = value; - } + explicit operator bool() const noexcept override { return m_result.has_value(); } - ///@brief Set a particular argument - /// - ///@tparam T Type of the argument to be set - ///@param arg_index The index (0 start) of the argument to change - ///@param value The value to set the argument to - template - void set_arg(size_t arg_index, T&& value) & + [[nodiscard]] R get_result() const { - if (m_args[arg_index].type() != typeid(T)) + if (m_result.has_value()) { - const std::string t_name = typeid(T).name(); - throw std::runtime_error("Invalid argument type: \"" + t_name + "\" provided!"); + return m_result.value(); } - m_args[arg_index] = std::move(value); + throw std::runtime_error(this->get_err_mesg()); } - ///@brief Set all arguments + ///@brief Set the result /// - ///@param args A tuple containing the list of arguments to set - void set_args(const std::tuple>...>& args) & - { - size_t i = 0; - details::for_each_tuple(args, [&i, this](auto x) { m_args[i++] = x; }); - } + ///@param value Value of type R to set as the result + void set_result(R value) & noexcept { m_result = std::move(value); } - ///@brief Get the arg object - /// - ///@tparam T Type to be acquired from the argument list (via std::any_cast) - ///@param arg_index The index (0 start) of the argument to retrieve - ///@return std::remove_cv_t> The argument's value - template - [[nodiscard]] std::remove_cv_t> get_arg(size_t arg_index) const - { - // TODO: Remove the remove_cv/remove_reference? - return std::any_cast>>(m_args[arg_index]); - } + ///@brief Sets the result back to null + void clear_result() & noexcept { m_result = std::nullopt; } private: - std::array m_args; - -#if defined(RPC_HPP_ENABLE_POINTERS) - std::array m_arg_sz_arr{}; - - template - void update_arg_arr_helper( - [[maybe_unused]] std::array&& arg_arr, size_t& count) & - { - if constexpr (std::is_pointer_v) - { - const auto& arr = std::any_cast< - const details::dyn_array>>&>( - std::move(arg_arr[count])); - - m_arg_sz_arr[count] = arr.capacity(); - } - - ++count; - } + std::optional m_result{ std::nullopt }; +}; +///@brief Class reprensenting a function call (with void result) including its name and parameters +/// +///@tparam Args The list of parameter type(s) +template +class packed_func final : public details::packed_func_base +{ public: - ///@brief Get the indexed argument size - /// - ///@param index The index to get the arg size for - ///@return size_t The size (number of elements) for the given argument - [[nodiscard]] size_t get_arg_arr_sz(const size_t index) const { return m_arg_sz_arr[index]; } - - ///@brief Set the size for the indexed argument - /// - ///@param index The index to set the arg size for - ///@param sz The size (number of elements) for the given argument - void set_arg_arr_sz(const size_t index, const size_t sz) & { m_arg_sz_arr[index] = sz; } + using result_type = void; + using typename details::packed_func_base::args_type; - ///@brief Update the argument size array - /// - ///@param arg_arr Array of arguments to reference - void update_arg_arr(std::array arg_arr) & + packed_func(std::string func_name, args_type args) + : details::packed_func_base(std::move(func_name), std::move(args)) { - size_t count = 0; - using expander = int[]; - (void)expander{ 0, ((void)update_arg_arr_helper(std::move(arg_arr), count), 0)... }; } -#endif + + packed_func(const packed_func&) = default; + packed_func(packed_func&&) noexcept = default; + packed_func& operator=(const packed_func&) & = default; + packed_func& operator=(packed_func&&) & = default; }; template @@ -916,6 +779,8 @@ class serial_adapter ///@return std::string The function name (case-sensitive) [[nodiscard]] static std::string extract_func_name(const value_type& obj); + static void set_err_mesg(doc_type& serial_obj, const std::string& str); + ///@brief Creates a serial object from inside another serial object /// ///@param obj The original object to extract the sub-object from @@ -930,8 +795,6 @@ class serial_adapter ///@return value_type The serial object representing an inner object of the original [[nodiscard]] static doc_type make_sub_object(const value_type& obj, const std::string& name); - // TODO: Change get_value to return std::optional? - ///@brief Extract a value from a serial object /// ///@tparam T The type of the object to extract @@ -1053,21 +916,6 @@ namespace details return arg_from_serial(sub_obj); } - ///@brief Unpacks the argument values from a \ref packed_func - /// - ///@tparam Value The type of the argument to be unpacked - ///@tparam R The type of the result for the \ref packed_func - ///@tparam Args The list of parameter type(s) for the \ref packed_func - ///@param pack The packaged function call to unpack - ///@param arg_index The index of the argument to be unpacked (is iterated in a parameter pack when called from a tuple) - ///@return std::remove_cv_t> The unpacked argument value - template - std::remove_cv_t> args_from_packed( - const packed_func& pack, unsigned& arg_index) - { - return pack.template get_arg>>(arg_index++); - } - #if defined(RPC_HPP_ENABLE_POINTERS) ///@brief Retrieves the argument values from a serial object (accepts pointers) /// @@ -1149,36 +997,6 @@ namespace details /// Client-side code should not need to use anything in this namespace namespace server { - ///@brief Converts a \ref packed_func_base to a specific templated \ref packed_func - /// - ///@tparam R Return type for the \ref packed_func - ///@tparam Args List of parameter type(s) for the \ref packed_func - ///@param unused Function object to derive R and Args from - ///@param pack packed_func_base reference to be converted - ///@return packed_func& A casted reference to a specific \ref packed_func - template - packed_func& convert_func( - [[maybe_unused]] std::function unused, const packed_func_base& pack) - { - return dynamic_cast&>(pack); - } - - ///@brief Converts a \ref packed_func_base to a specific templated \ref packed_func - /// - ///@tparam R Return type for the \ref packed_func - ///@tparam Args List of parameter type(s) for the \ref packed_func - ///@param unused Function pointer to derive R and Args from - ///@param pack packed_func_base reference to be converted - ///@return packed_func& A casted reference to a specific \ref packed_func - template - packed_func& convert_func( - [[maybe_unused]] R (*unused)(Args...), const packed_func_base& pack) - { - return dynamic_cast&>(pack); - } - - // TODO: Server-side asynchronous functions (will probably have to return vs. reference) - ///@brief Create a \ref packed_func object from a serial object /// ///@tparam Serial The type of serial object @@ -1198,40 +1016,33 @@ namespace server /// ///@tparam R The type of the result for the function call ///@tparam Args The list of parameter type(s) for the function call - ///@param func The function object to call + ///@param func Pointer to the function to call ///@param pack The packaged function call to get/set result and/or parameters template - void run_callback(std::function func, packed_func& pack) + void run_callback(R (*func)(Args...), packed_func& pack) { - unsigned arg_count = 0; - - std::tuple>...> args{ - details::args_from_packed(pack, arg_count)... - }; + auto args = pack.get_args(); if constexpr (std::is_void_v) { std::apply(func, args); - pack.set_args(args); + pack.set_args(std::move(args)); } else { - auto result = std::apply(func, args); - pack.set_args(args); - pack.set_result(result); - } - } + try + { + auto result = std::apply(func, args); + pack.set_result(std::move(result)); + } + catch (const std::exception&) + { + pack.clear_result(); + throw; + } - ///@brief Runs the callback function and populates the \ref packed_func with the result and/or updated arguments - /// - ///@tparam R The type of the result for the function call - ///@tparam Args The list of parameter type(s) for the function call - ///@param func Pointer to the function to call - ///@param pack The packaged function call to get/set result and/or parameters - template - void run_callback(R (*func)(Args...), packed_func& pack) - { - return run_callback(std::function(func), pack); + pack.set_args(std::move(args)); + } } #if defined(RPC_HPP_ENABLE_POINTERS) @@ -1302,42 +1113,61 @@ namespace server void dispatch_func( R (*func)(Args...), typename Serial::doc_type& serial_obj, bool cacheable = false) { -#if defined(RPC_HPP_ENABLE_SERVER_CACHE) - if constexpr (!std::is_void_v) + try { - if (cacheable && check_cache(serial_obj)) +#if defined(RPC_HPP_ENABLE_SERVER_CACHE) + if constexpr (!std::is_void_v) { - return; + if (cacheable && check_cache(serial_obj)) + { + return; + } } - } #endif #if defined(RPC_HPP_ENABLE_POINTERS) - if constexpr ( - details::all_true_v>> || std::is_array_v>>)...>) - { - auto pack = create_func(func, serial_obj); - run_callback(func, pack); + if constexpr ( + details::all_true_v>> || std::is_array_v>>)...>) + { + auto pack = create_func(func, serial_obj); + run_callback(func, pack); # if defined(RPC_HPP_ENABLE_SERVER_CACHE) - if constexpr (!std::is_void_v) - { - if (cacheable) + if constexpr (!std::is_void_v) { - update_cache( - serial_adapter::to_string(serial_obj), *pack.get_result()); + if (cacheable) + { + update_cache( + serial_adapter::to_string(serial_obj), pack.get_result()); + } } +# endif + + serial_obj = serial_adapter::from_packed_func(std::move(pack)); } + else + { + const auto arg_arr = details::populate_arg_arr(serial_obj); + auto pack = create_func_w_ptr(func, arg_arr, serial_obj); + run_callback(func, pack); + +# if defined(RPC_HPP_ENABLE_SERVER_CACHE) + if constexpr (!std::is_void_v) + { + if (cacheable) + { + update_cache( + serial_adapter::to_string(serial_obj), pack.get_result()); + } + } # endif - serial_obj = serial_adapter::from_packed_func(std::move(pack)); - } - else - { - const auto arg_arr = details::populate_arg_arr(serial_obj); - auto pack = create_func_w_ptr(func, arg_arr, serial_obj); + serial_obj = serial_adapter::from_packed_func(std::move(pack)); + } +#else + auto pack = create_func(func, serial_obj); run_callback(func, pack); # if defined(RPC_HPP_ENABLE_SERVER_CACHE) @@ -1346,30 +1176,18 @@ namespace server if (cacheable) { update_cache( - serial_adapter::to_string(serial_obj), *pack.get_result()); + serial_adapter::to_string(serial_obj), pack.get_result()); } } # endif serial_obj = serial_adapter::from_packed_func(std::move(pack)); +#endif } -#else - auto pack = create_func(func, serial_obj); - run_callback(func, pack); - -# if defined(RPC_HPP_ENABLE_SERVER_CACHE) - if constexpr (!std::is_void_v) + catch (const std::exception& ex) { - if (cacheable) - { - update_cache( - serial_adapter::to_string(serial_obj), *pack.get_result()); - } + serial_adapter::set_err_mesg(serial_obj, ex.what()); } -# endif - - serial_obj = serial_adapter::from_packed_func(std::move(pack)); -#endif } } // namespace rpc::server @@ -1430,11 +1248,13 @@ inline namespace client std::array arg_sz_arr{}; unsigned i = 0; - std::array argArray{ pack_arg(args, arg_sz_arr.data(), i)... }; + typename packed_func...>::args_type argTup{ pack_arg( + args, arg_sz_arr.data(), i)... }; if constexpr (std::is_void_v) { - packed_func...> pack(std::move(func_name), argArray); + packed_func...> pack( + std::move(func_name), std::move(argTup)); for (size_t j = 0; j < sizeof...(Args); ++j) { @@ -1446,7 +1266,7 @@ inline namespace client else { packed_func...> pack( - std::move(func_name), std::nullopt, argArray); + std::move(func_name), std::nullopt, std::move(argTup)); for (size_t j = 0; j < sizeof...(Args); ++j) { @@ -1491,7 +1311,6 @@ inline namespace client template typename Serial::doc_type serialize_call(std::string&& func_name, Args&&... args) { - // TODO: Can we elminate creating a packed_func JUST to serialize it back? auto packed = pack_call(std::move(func_name), std::forward(args)...); return serial_adapter::template from_packed_func...>( @@ -1609,10 +1428,9 @@ inline namespace client details::all_true_v>> || std::is_array_v>>)...>, - "Calling functions with pointer arguments is disabled by default as it adds " - "overhead, " - "please consider refactoring your API to avoid pointers. If you must use pointers, " - "define 'RPC_HPP_ENABLE_POINTERS'."); + "Calling functions with pointer arguments is disabled by default as it adds overhead, " + "please consider refactoring your API to avoid pointers." + "If you must use pointers, define 'RPC_HPP_ENABLE_POINTERS'."); const auto serial_obj = serialize_call(std::move(func_name), std::forward(args)...); diff --git a/include/rpc_adapters/rpc_boost_json.hpp b/include/rpc_adapters/rpc_boost_json.hpp index 8fcc59a5..7c6a9614 100644 --- a/include/rpc_adapters/rpc_boost_json.hpp +++ b/include/rpc_adapters/rpc_boost_json.hpp @@ -1,7 +1,7 @@ ///@file rpc_adapters/rpc_boost_json.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Implementation of adapting Boost.JSON (https://github.com/boostorg/json) -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -62,12 +62,20 @@ rpc::packed_func bjson_adapter::to_packed_func(const bjson_val& seri const auto& obj = serial_obj.as_object(); unsigned i = 0; - std::array args{ details::args_from_serial( - obj, i)... }; + typename rpc::packed_func::args_type args{ + details::args_from_serial(obj, i)... + }; if constexpr (std::is_void_v) { - return packed_func(obj.at("func_name").get_string().c_str(), args); + packed_func pack(obj.at("func_name").get_string().c_str(), std::move(args)); + + if (obj.contains("err_mesg")) + { + pack.set_err_mesg(obj.at("err_mesg").get_string().c_str()); + } + + return pack; } else { @@ -77,30 +85,37 @@ rpc::packed_func bjson_adapter::to_packed_func(const bjson_val& seri if constexpr (std::is_arithmetic_v) { - return packed_func( - obj.at("func_name").get_string().c_str(), bjson::value_to(result), args); + return packed_func(obj.at("func_name").get_string().c_str(), + bjson::value_to(result), std::move(args)); } else if constexpr (std::is_same_v) { - return packed_func( - obj.at("func_name").get_string().c_str(), result.get_string().c_str(), args); + return packed_func(obj.at("func_name").get_string().c_str(), + result.get_string().c_str(), std::move(args)); } else if constexpr (details::is_container_v) { R container; populate_array(result, container); return packed_func( - obj.at("func_name").get_string().c_str(), container, args); + obj.at("func_name").get_string().c_str(), container, std::move(args)); } else { return packed_func(obj.at("func_name").get_string().c_str(), - deserialize(result), args); + deserialize(result), std::move(args)); } } - return packed_func( - obj.at("func_name").get_string().c_str(), std::nullopt, args); + packed_func pack( + obj.at("func_name").get_string().c_str(), std::nullopt, std::move(args)); + + if (obj.contains("err_mesg")) + { + pack.set_err_mesg(obj.at("err_mesg").get_string().c_str()); + } + + return pack; } } @@ -158,21 +173,29 @@ bjson_val bjson_adapter::from_packed_func(packed_func&& pack) bjson_obj ret_j; ret_j["func_name"] = pack.get_func_name(); - ret_j["result"] = nullptr; - auto& result = ret_j["result"]; + + const auto err_mesg = pack.get_err_mesg(); + + if (!err_mesg.empty()) + { + ret_j["err_mesg"] = err_mesg; + } if constexpr (!std::is_void_v) { + ret_j["result"] = nullptr; + auto& result = ret_j["result"]; + if (pack) { if constexpr (std::is_arithmetic_v || std::is_same_v) { - result = *pack.get_result(); + result = pack.get_result(); } else if constexpr (details::is_container_v) { result = bjson::array{}; - const auto container = *pack.get_result(); + const auto container = pack.get_result(); for (const auto& val : container) { @@ -181,7 +204,7 @@ bjson_val bjson_adapter::from_packed_func(packed_func&& pack) } else { - result = serialize(*pack.get_result()); + result = serialize(pack.get_result()); } } } @@ -190,9 +213,7 @@ bjson_val bjson_adapter::from_packed_func(packed_func&& pack) auto& args = ret_j["args"].as_array(); unsigned i = 0; - std::tuple>...> argTup{ - details::args_from_packed(pack, i)... - }; + const auto& argTup = pack.get_args(); # if defined(RPC_HPP_ENABLE_POINTERS) i = 0; @@ -227,6 +248,14 @@ inline std::string bjson_adapter::extract_func_name(const bjson_val& obj) return obj.at("func_name").get_string().c_str(); } +template<> +inline void bjson_adapter::set_err_mesg(bjson_val& serial_obj, const std::string& str) +{ + assert(serial_obj.is_object()); + serial_obj["result"] = nullptr; + serial_obj["err_mesg"] = str; +} + template<> inline bjson_val bjson_adapter::make_sub_object(const bjson_val& obj, const unsigned index) { @@ -309,7 +338,7 @@ rpc::packed_func bjson_adapter::to_packed_func_w_ptr( auto& obj = serial_obj.as_object(); unsigned i = 0; - std::array args{ + typename rpc::packed_func::args_type args{ details::args_from_serial_w_ptr(serial_obj, arg_arr, i)... }; @@ -318,7 +347,7 @@ rpc::packed_func bjson_adapter::to_packed_func_w_ptr( if constexpr (std::is_void_v) { pack_ptr = std::make_unique>( - obj.at("func_name").get_string().c_str(), args); + obj.at("func_name").get_string().c_str(), std::move(args)); } else { @@ -329,31 +358,33 @@ rpc::packed_func bjson_adapter::to_packed_func_w_ptr( if constexpr (std::is_arithmetic_v) { pack_ptr = std::make_unique>( - obj.at("func_name").get_string().c_str(), bjson::value_to(result), args); + obj.at("func_name").get_string().c_str(), bjson::value_to(result), + std::move(args)); } else if constexpr (std::is_same_v) { pack_ptr = std::make_unique>( - obj.at("func_name").get_string().c_str(), result.get_string().c_str(), args); + obj.at("func_name").get_string().c_str(), result.get_string().c_str(), + std::move(args)); } else if constexpr (details::is_container_v) { R container; populate_array(result, container); pack_ptr = std::make_unique>( - obj.at("func_name").get_string().c_str(), container, args); + obj.at("func_name").get_string().c_str(), container, std::move(args)); } else { pack_ptr = std::make_unique>( obj.at("func_name").get_string().c_str(), - deserialize(result), args); + deserialize(result), std::move(args)); } } else { pack_ptr = std::make_unique>( - obj.at("func_name").get_string().c_str(), std::nullopt, args); + obj.at("func_name").get_string().c_str(), std::nullopt, std::move(args)); } } diff --git a/include/rpc_adapters/rpc_njson.hpp b/include/rpc_adapters/rpc_njson.hpp index 9a3b610b..574d622b 100644 --- a/include/rpc_adapters/rpc_njson.hpp +++ b/include/rpc_adapters/rpc_njson.hpp @@ -1,7 +1,7 @@ ///@file rpc_adapters/rpc_njson.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Implementation of adapting nlohmann/json (https://github.com/nlohmann/json) -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -64,22 +64,37 @@ rpc::packed_func njson_adapter::to_packed_func(const njson& serial_o { unsigned i = 0; - std::array args{ details::args_from_serial( - serial_obj, i)... }; + typename rpc::packed_func::args_type args{ + details::args_from_serial(serial_obj, i)... + }; if constexpr (!std::is_void_v) { if (serial_obj.contains("result") && !serial_obj["result"].is_null()) { return packed_func( - serial_obj["func_name"], serial_obj["result"].get(), args); + serial_obj["func_name"], serial_obj["result"].get(), std::move(args)); } - return packed_func(serial_obj["func_name"], std::nullopt, args); + packed_func pack(serial_obj["func_name"], std::nullopt, std::move(args)); + + if (serial_obj.contains("err_mesg")) + { + pack.set_err_mesg(serial_obj["err_mesg"]); + } + + return pack; } else { - return packed_func(serial_obj["func_name"], args); + packed_func pack(serial_obj["func_name"], std::move(args)); + + if (serial_obj.contains("err_mesg")) + { + pack.set_err_mesg(serial_obj["err_mesg"]); + } + + return pack; } } @@ -142,23 +157,31 @@ njson njson_adapter::from_packed_func(packed_func&& pack) njson ret_j; ret_j["func_name"] = pack.get_func_name(); - ret_j["result"] = nullptr; + + const auto err_mesg = pack.get_err_mesg(); + + if (!err_mesg.empty()) + { + ret_j["err_mesg"] = err_mesg; + } // TODO: Address use of containers/custom types for result if constexpr (!std::is_void_v) { if (pack) { - ret_j["result"] = *pack.get_result(); + ret_j["result"] = pack.get_result(); + } + else + { + ret_j["result"] = nullptr; } } ret_j["args"] = njson::array(); unsigned i = 0; - std::tuple>...> argTup{ - details::args_from_packed(pack, i)... - }; + const auto& argTup = pack.get_args(); # if defined(RPC_HPP_ENABLE_POINTERS) i = 0; @@ -192,6 +215,13 @@ inline std::string njson_adapter::extract_func_name(const njson& obj) return obj["func_name"].get(); } +template<> +inline void njson_adapter::set_err_mesg(njson& serial_obj, const std::string& str) +{ + serial_obj["result"] = nullptr; + serial_obj["err_mesg"] = str; +} + template<> inline njson njson_adapter::make_sub_object(const njson& obj, const unsigned index) { @@ -248,7 +278,7 @@ rpc::packed_func njson_adapter::to_packed_func_w_ptr( { unsigned i = 0; - std::array args{ + typename rpc::packed_func::args_type args{ details::args_from_serial_w_ptr(serial_obj, arg_arr, i)... }; @@ -259,17 +289,18 @@ rpc::packed_func njson_adapter::to_packed_func_w_ptr( if (serial_obj.contains("result") && !serial_obj["result"].is_null()) { pack_ptr = std::make_unique>( - serial_obj["func_name"], serial_obj["result"].get(), args); + serial_obj["func_name"], serial_obj["result"].get(), std::move(args)); } else { pack_ptr = std::make_unique>( - serial_obj["func_name"], std::nullopt, args); + serial_obj["func_name"], std::nullopt, std::move(args)); } } else { - pack_ptr = std::make_unique>(serial_obj["func_name"], args); + pack_ptr = + std::make_unique>(serial_obj["func_name"], std::move(args)); } pack_ptr->update_arg_arr(arg_arr); @@ -376,21 +407,37 @@ rpc::packed_func generic_serial_adapter::to_packed_func(const byte_v unsigned i = 0; const njson j_obj = from_func(serial_obj); - std::array args{ details::args_from_serial( - serial_obj, i)... }; + typename rpc::packed_func::args_type args{ + details::args_from_serial(serial_obj, i)... + }; if constexpr (!std::is_void_v) { if (j_obj.contains("result") && !j_obj["result"].is_null()) { - return packed_func(j_obj["func_name"], j_obj["result"].get(), args); + return packed_func( + j_obj["func_name"], j_obj["result"].get(), std::move(args)); } - return packed_func(j_obj["func_name"], std::nullopt, args); + packed_func pack(j_obj["func_name"], std::nullopt, std::move(args)); + + if (j_obj.contains("err_mesg")) + { + pack.set_err_mesg(j_obj["err_mesg"]); + } + + return pack; } else { - return packed_func(j_obj["func_name"], args); + packed_func pack(j_obj["func_name"], std::move(args)); + + if (j_obj.contains("err_mesg")) + { + pack.set_err_mesg(j_obj["err_mesg"]); + } + + return pack; } } @@ -401,22 +448,30 @@ byte_vec generic_serial_adapter::from_packed_func(packed_func&& pack njson ret_j; ret_j["func_name"] = pack.get_func_name(); - ret_j["result"] = nullptr; + + const auto err_mesg = pack.get_err_mesg(); + + if (!err_mesg.empty()) + { + ret_j["err_mesg"] = err_mesg; + } if constexpr (!std::is_void_v) { if (pack) { - ret_j["result"] = *pack.get_result(); + ret_j["result"] = pack.get_result(); + } + else + { + ret_j["result"] = nullptr; } } ret_j["args"] = njson::array(); unsigned i = 0; - std::tuple>...> argTup{ - details::args_from_packed(pack, i)... - }; + const auto& argTup = pack.get_args(); # if defined(RPC_HPP_ENABLE_POINTERS) i = 0; @@ -450,6 +505,16 @@ inline std::string generic_serial_adapter::extract_func_name(const byte_vec& obj return from_func(obj)["func_name"].get(); } +template<> +inline void generic_serial_adapter::set_err_mesg(byte_vec& serial_obj, const std::string& str) +{ + auto obj_j = from_func(serial_obj); + + obj_j["result"] = nullptr; + obj_j["err_mesg"] = str; + serial_obj = to_func(obj_j); +} + template<> inline byte_vec generic_serial_adapter::make_sub_object(const byte_vec& obj, const unsigned index) { @@ -512,7 +577,7 @@ rpc::packed_func generic_serial_adapter::to_packed_func_w_ptr( unsigned i = 0; const njson j_obj = from_func(serial_obj); - std::array args{ + typename rpc::packed_func::args_type args{ details::args_from_serial_w_ptr(serial_obj, arg_arr, i)... }; @@ -523,15 +588,16 @@ rpc::packed_func generic_serial_adapter::to_packed_func_w_ptr( if (j_obj.contains("result") && !j_obj["result"].is_null()) { pack_ptr = std::make_unique>( - j_obj["func_name"], j_obj["result"].get(), args); + j_obj["func_name"], j_obj["result"].get(), std::move(args)); } - pack_ptr = - std::make_unique>(j_obj["func_name"], std::nullopt, args); + pack_ptr = std::make_unique>( + j_obj["func_name"], std::nullopt, std::move(args)); } else { - pack_ptr = std::make_unique>(j_obj["func_name"], args); + pack_ptr = + std::make_unique>(j_obj["func_name"], std::move(args)); } pack_ptr->update_arg_arr(arg_arr); diff --git a/include/rpc_adapters/rpc_rapidjson.hpp b/include/rpc_adapters/rpc_rapidjson.hpp index 5e9b87df..be997f1d 100644 --- a/include/rpc_adapters/rpc_rapidjson.hpp +++ b/include/rpc_adapters/rpc_rapidjson.hpp @@ -1,7 +1,7 @@ ///@file rpc_adapters/rpc_rapidjson.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Implementation of adapting rapidjson (https://github.com/Tencent/rapidjson) -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -60,12 +60,20 @@ rpc::packed_func rpdjson_adapter::to_packed_func(const rpdjson_doc& { unsigned i = 0; - std::array args{ details::args_from_serial( - serial_obj, i)... }; + typename rpc::packed_func::args_type args{ + details::args_from_serial(serial_obj, i)... + }; if constexpr (std::is_void_v) { - return packed_func(serial_obj["func_name"].GetString(), args); + packed_func pack(serial_obj["func_name"].GetString(), std::move(args)); + + if (serial_obj.HasMember("err_mesg")) + { + pack.set_err_mesg(serial_obj["err_mesg"].GetString()); + } + + return pack; } else { @@ -75,21 +83,28 @@ rpc::packed_func rpdjson_adapter::to_packed_func(const rpdjson_doc& if (result.IsNull()) { - return packed_func( - serial_obj["func_name"].GetString(), std::nullopt, args); + packed_func pack( + serial_obj["func_name"].GetString(), std::nullopt, std::move(args)); + + if (serial_obj.HasMember("err_mesg")) + { + pack.set_err_mesg(serial_obj["err_mesg"].GetString()); + } + + return pack; } if constexpr (std::is_same_v) { return packed_func( - serial_obj["func_name"].GetString(), result.GetString(), args); + serial_obj["func_name"].GetString(), result.GetString(), std::move(args)); } else if constexpr (details::is_container_v) { R container; populate_array(result, container); return packed_func( - serial_obj["func_name"].GetString(), container, args); + serial_obj["func_name"].GetString(), container, std::move(args)); } else if constexpr (std::is_arithmetic_v) { @@ -97,23 +112,23 @@ rpc::packed_func rpdjson_adapter::to_packed_func(const rpdjson_doc& char> || std::is_same_v || std::is_same_v) { return packed_func( - serial_obj["func_name"].GetString(), result.GetInt(), args); + serial_obj["func_name"].GetString(), result.GetInt(), std::move(args)); } else if constexpr (std::is_same_v || std::is_same_v) { return packed_func( - serial_obj["func_name"].GetString(), result.GetUint(), args); + serial_obj["func_name"].GetString(), result.GetUint(), std::move(args)); } else { return packed_func( - serial_obj["func_name"].GetString(), result.Get(), args); + serial_obj["func_name"].GetString(), result.Get(), std::move(args)); } } else if constexpr (details::is_serializable_v) { return packed_func( - serial_obj["func_name"].GetString(), R::deserialize(result), args); + serial_obj["func_name"].GetString(), R::deserialize(result), std::move(args)); } else { @@ -122,7 +137,15 @@ rpc::packed_func rpdjson_adapter::to_packed_func(const rpdjson_doc& } } - return packed_func(serial_obj["func_name"].GetString(), std::nullopt, args); + packed_func pack( + serial_obj["func_name"].GetString(), std::nullopt, std::move(args)); + + if (serial_obj.HasMember("err_mesg")) + { + pack.set_err_mesg(serial_obj["err_mesg"].GetString()); + } + + return pack; } } @@ -219,27 +242,32 @@ rpdjson_doc rpdjson_adapter::from_packed_func(packed_func&& pack) func_name.SetString(pack.get_func_name().c_str(), alloc); d.AddMember("func_name", func_name, alloc); - rpdjson_val result; + const auto err_mesg = pack.get_err_mesg(); - if constexpr (std::is_void_v) + if (!err_mesg.empty()) { - result.SetNull(); + rpdjson_val err_mesg_val; + err_mesg_val.SetString(err_mesg.c_str(), alloc); + d.AddMember("err_mesg", err_mesg_val, alloc); } - else + + if constexpr (!std::is_void_v) { + rpdjson_val result; + if (pack) { if constexpr (std::is_arithmetic_v) { - result.Set(*pack.get_result()); + result.Set(pack.get_result()); } else if constexpr (std::is_same_v) { - result.SetString(pack.get_result()->c_str(), alloc); + result.SetString(pack.get_result().c_str(), alloc); } else if constexpr (details::is_container_v) { - const R container = *pack.get_result(); + const R container = pack.get_result(); result.SetArray(); for (const auto& val : container) @@ -249,12 +277,12 @@ rpdjson_doc rpdjson_adapter::from_packed_func(packed_func&& pack) } else if constexpr (details::is_serializable_v) { - rpdjson_doc tmp = R::serialize(*pack.get_result()); + rpdjson_doc tmp = R::serialize(pack.get_result()); result.CopyFrom(tmp, alloc); } else { - rpdjson_doc tmp = serialize(*pack.get_result()); + rpdjson_doc tmp = serialize(pack.get_result()); result.CopyFrom(tmp, alloc); } } @@ -262,17 +290,15 @@ rpdjson_doc rpdjson_adapter::from_packed_func(packed_func&& pack) { result.SetNull(); } - } - d.AddMember("result", result, alloc); + d.AddMember("result", result, alloc); + } rpdjson_val args; args.SetArray(); unsigned i = 0; - std::tuple>...> argTup{ - details::args_from_packed(pack, i)... - }; + const auto& argTup = pack.get_args(); # if defined(RPC_HPP_ENABLE_POINTERS) i = 0; @@ -313,6 +339,28 @@ inline std::string rpdjson_adapter::extract_func_name(const rpdjson_val& obj) return obj["func_name"].GetString(); } +template<> +inline void rpdjson_adapter::set_err_mesg(rpdjson_doc& serial_obj, const std::string& str) +{ + auto& alloc = serial_obj.GetAllocator(); + + if (serial_obj.HasMember("result")) + { + serial_obj["result"].SetNull(); + } + + if (serial_obj.HasMember("err_mesg")) + { + serial_obj["err_mesg"].SetString(str.c_str(), alloc); + } + else + { + rpdjson_val val; + val.SetString(str.c_str(), alloc); + serial_obj.AddMember("err_mesg", val, alloc); + } +} + template<> inline rpdjson_doc rpdjson_adapter::make_sub_object(const rpdjson_val& obj, const unsigned index) { @@ -438,7 +486,7 @@ rpc::packed_func rpdjson_adapter::to_packed_func_w_ptr( { unsigned i = 0; - std::array args{ + typename rpc::packed_func::args_type args{ details::args_from_serial_w_ptr(serial_obj, arg_arr, i)... }; @@ -446,8 +494,8 @@ rpc::packed_func rpdjson_adapter::to_packed_func_w_ptr( if constexpr (std::is_void_v) { - pack_ptr = - std::make_unique>(serial_obj["func_name"].GetString(), args); + pack_ptr = std::make_unique>( + serial_obj["func_name"].GetString(), std::move(args)); } else { @@ -458,25 +506,25 @@ rpc::packed_func rpdjson_adapter::to_packed_func_w_ptr( if constexpr (std::is_same_v) { pack_ptr = std::make_unique>( - serial_obj["func_name"].GetString(), result.GetString(), args); + serial_obj["func_name"].GetString(), result.GetString(), std::move(args)); } else if constexpr (details::is_container_v) { R container; populate_array(result, container); pack_ptr = std::make_unique>( - serial_obj["func_name"].GetString(), container, args); + serial_obj["func_name"].GetString(), container, std::move(args)); } else { pack_ptr = std::make_unique>( - serial_obj["func_name"].GetString(), result.Get(), args); + serial_obj["func_name"].GetString(), result.Get(), std::move(args)); } } else { pack_ptr = std::make_unique>( - serial_obj["func_name"].GetString(), std::nullopt, args); + serial_obj["func_name"].GetString(), std::nullopt, std::move(args)); } } diff --git a/include/rpc_dispatch_helper.hpp b/include/rpc_dispatch_helper.hpp index 0d62eb69..036457a4 100644 --- a/include/rpc_dispatch_helper.hpp +++ b/include/rpc_dispatch_helper.hpp @@ -82,4 +82,4 @@ #define RPC_ALIAS_CACHED_FUNC(FUNCNAME, FUNC_ALIAS) if (func_name == #FUNC_ALIAS) { return dispatch_func(FUNCNAME, serial_obj, true); } #define RPC_MULTI_ALIAS_CACHED_FUNC(FUNCNAME, FUNC_ALIAS,...) EXPAND(RPC_FOR_EACH2(RPC_ALIAS_CACHED_FUNC, FUNCNAME, FUNC_ALIAS, __VA_ARGS__)) -#define RPC_DEFAULT_DISPATCH(FUNCNAME, ...) EXPAND(template void rpc::server::dispatch(typename Serial::doc_type& serial_obj) { const auto func_name = serial_adapter::extract_func_name(serial_obj); RPC_ATTACH_FUNCS(FUNCNAME, __VA_ARGS__) throw std::runtime_error("RPC error: Called function: \"" + func_name + "\" not found!");}) +#define RPC_DEFAULT_DISPATCH(FUNCNAME, ...) EXPAND(template void rpc::server::dispatch(typename Serial::doc_type& serial_obj) { const auto func_name = serial_adapter::extract_func_name(serial_obj); RPC_ATTACH_FUNCS(FUNCNAME, __VA_ARGS__) serial_adapter::set_err_mesg(serial_obj, "RPC error: Called function: \"" + func_name + "\" not found!");}) diff --git a/meson.build b/meson.build index d20ab97e..187b10c4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('rpc.hpp', 'cpp', - version : '0.3.1', + version : '0.3.3', license : 'BSD-3-Clause', default_options : [ 'cpp_std=c++17', diff --git a/tests/rpc.benchmark.cpp b/tests/rpc.benchmark.cpp index a374497e..c7cd7206 100644 --- a/tests/rpc.benchmark.cpp +++ b/tests/rpc.benchmark.cpp @@ -1,7 +1,7 @@ ///@file rpc.benchmark.cpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Benchmarking source file for rpc.hpp -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -99,8 +99,8 @@ TEST_CASE("By Value (simple)", "[value][simple][cached]") BENCHMARK("rpc.hpp (asio::tcp, njson)") { - test = *rpc::call(GetClient(), "Fibonacci", 20) - .get_result(); + test = rpc::call(GetClient(), "Fibonacci", 20) + .get_result(); }; REQUIRE(expected == test); @@ -110,9 +110,8 @@ TEST_CASE("By Value (simple)", "[value][simple][cached]") BENCHMARK("rpc.hpp (asio::tcp, rapidjson)") { - test = - *rpc::call(GetClient(), "Fibonacci", 20) - .get_result(); + test = rpc::call(GetClient(), "Fibonacci", 20) + .get_result(); }; REQUIRE(expected == test); @@ -123,8 +122,8 @@ TEST_CASE("By Value (simple)", "[value][simple][cached]") BENCHMARK("rpc.hpp (asio::tcp, Boost.JSON)") { - test = *rpc::call(GetClient(), "Fibonacci", 20) - .get_result(); + test = rpc::call(GetClient(), "Fibonacci", 20) + .get_result(); }; REQUIRE(expected == test); @@ -146,8 +145,8 @@ TEST_CASE("By Value (complex)", "[value][complex][cached]") cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; test = - *rpc::call(GetClient(), "HashComplex", cx) - .get_result(); + rpc::call(GetClient(), "HashComplex", cx) + .get_result(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -164,9 +163,9 @@ TEST_CASE("By Value (complex)", "[value][complex][cached]") cx.name = "Franklin D. Roosevelt"; cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; - test = *rpc::call( + test = rpc::call( GetClient(), "HashComplex", cx) - .get_result(); + .get_result(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -185,8 +184,8 @@ TEST_CASE("By Value (complex)", "[value][complex][cached]") cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; test = - *rpc::call(GetClient(), "HashComplex", cx) - .get_result(); + rpc::call(GetClient(), "HashComplex", cx) + .get_result(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -200,9 +199,9 @@ TEST_CASE("By Value (many)", "[value][many][cached]") BENCHMARK("rpc.hpp (asio::tcp, njson)") { - test = *rpc::call(GetClient(), "StdDev", 55.65, + test = rpc::call(GetClient(), "StdDev", 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1) - .get_result(); + .get_result(); }; REQUIRE_THAT(test, Catch::Matchers::WithinRel(expected)); @@ -212,9 +211,9 @@ TEST_CASE("By Value (many)", "[value][many][cached]") BENCHMARK("rpc.hpp (asio::tcp, rapidjson)") { - test = *rpc::call(GetClient(), "StdDev", 55.65, + test = rpc::call(GetClient(), "StdDev", 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1) - .get_result(); + .get_result(); }; REQUIRE_THAT(test, Catch::Matchers::WithinRel(expected)); @@ -225,9 +224,9 @@ TEST_CASE("By Value (many)", "[value][many][cached]") BENCHMARK("rpc.hpp (asio::tcp, Boost.JSON)") { - test = *rpc::call(GetClient(), "StdDev", 55.65, + test = rpc::call(GetClient(), "StdDev", 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1) - .get_result(); + .get_result(); }; REQUIRE_THAT(test, Catch::Matchers::WithinRel(expected)); @@ -243,7 +242,7 @@ TEST_CASE("By Reference (simple)", "[ref][simple]") { uint64_t num = 20; test = rpc::call(GetClient(), "FibonacciRef", num) - .get_arg(0); + .get_arg(); }; REQUIRE(expected == test); @@ -255,7 +254,7 @@ TEST_CASE("By Reference (simple)", "[ref][simple]") { uint64_t num = 20; test = rpc::call(GetClient(), "FibonacciRef", num) - .get_arg(0); + .get_arg(); }; #endif @@ -268,7 +267,7 @@ TEST_CASE("By Reference (simple)", "[ref][simple]") { uint64_t num = 20; test = rpc::call(GetClient(), "FibonacciRef", num) - .get_arg(0); + .get_arg(); }; REQUIRE(expected == test); @@ -290,7 +289,7 @@ TEST_CASE("By Reference (complex)", "[ref][complex]") cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; test = rpc::call(GetClient(), "HashComplexRef", cx, test) - .get_arg(1); + .get_arg(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -309,7 +308,7 @@ TEST_CASE("By Reference (complex)", "[ref][complex]") test = rpc::call(GetClient(), "HashComplexRef", cx, test) - .get_arg(1); + .get_arg(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -328,7 +327,7 @@ TEST_CASE("By Reference (complex)", "[ref][complex]") cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; test = rpc::call(GetClient(), "HashComplexRef", cx, test) - .get_arg(1); + .get_arg(); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -356,16 +355,16 @@ TEST_CASE("By Reference (many)", "[ref][many]") const auto pack = rpc::call( GetClient(), "SquareRootRef", n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); - n1 = pack.get_arg(0); - n2 = pack.get_arg(1); - n3 = pack.get_arg(2); - n4 = pack.get_arg(3); - n5 = pack.get_arg(4); - n6 = pack.get_arg(5); - n7 = pack.get_arg(6); - n8 = pack.get_arg(7); - n9 = pack.get_arg(8); - n10 = pack.get_arg(9); + n1 = pack.get_arg(); + n2 = pack.get_arg(); + n3 = pack.get_arg(); + n4 = pack.get_arg(); + n5 = pack.get_arg(); + n6 = pack.get_arg(); + n7 = pack.get_arg(); + n8 = pack.get_arg(); + n9 = pack.get_arg(); + n10 = pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -390,16 +389,16 @@ TEST_CASE("By Reference (many)", "[ref][many]") const auto pack = rpc::call(GetClient(), "SquareRootRef", n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); - n1 = pack.get_arg(0); - n2 = pack.get_arg(1); - n3 = pack.get_arg(2); - n4 = pack.get_arg(3); - n5 = pack.get_arg(4); - n6 = pack.get_arg(5); - n7 = pack.get_arg(6); - n8 = pack.get_arg(7); - n9 = pack.get_arg(8); - n10 = pack.get_arg(9); + n1 = pack.get_arg(); + n2 = pack.get_arg(); + n3 = pack.get_arg(); + n4 = pack.get_arg(); + n5 = pack.get_arg(); + n6 = pack.get_arg(); + n7 = pack.get_arg(); + n8 = pack.get_arg(); + n9 = pack.get_arg(); + n10 = pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -425,16 +424,16 @@ TEST_CASE("By Reference (many)", "[ref][many]") const auto pack = rpc::call( GetClient(), "SquareRootRef", n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); - n1 = pack.get_arg(0); - n2 = pack.get_arg(1); - n3 = pack.get_arg(2); - n4 = pack.get_arg(3); - n5 = pack.get_arg(4); - n6 = pack.get_arg(5); - n7 = pack.get_arg(6); - n8 = pack.get_arg(7); - n9 = pack.get_arg(8); - n10 = pack.get_arg(9); + n1 = pack.get_arg(); + n2 = pack.get_arg(); + n3 = pack.get_arg(); + n4 = pack.get_arg(); + n5 = pack.get_arg(); + n6 = pack.get_arg(); + n7 = pack.get_arg(); + n8 = pack.get_arg(); + n9 = pack.get_arg(); + n10 = pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -452,9 +451,9 @@ TEST_CASE("With Container", "[container][cached]") const std::vector vec{ 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1 }; - test = *rpc::call( + test = rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; REQUIRE_THAT(test, Catch::Matchers::WithinAbs(expected, 0.001)); @@ -467,9 +466,9 @@ TEST_CASE("With Container", "[container][cached]") const std::vector vec{ 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1 }; - test = *rpc::call( + test = rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; #endif @@ -481,9 +480,9 @@ TEST_CASE("With Container", "[container][cached]") const std::vector vec{ 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1 }; - test = *rpc::call( + test = rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; #endif } @@ -492,59 +491,57 @@ TEST_CASE("Sequential", "[sequential][cached]") { BENCHMARK("rpc.hpp (asio::tcp, njson)") { - auto vec = *rpc::call>( + auto vec = rpc::call>( GetClient(), "RandInt", 5, 30, 1000) - .get_result(); + .get_result(); for (auto& val : vec) { - val = - *rpc::call(GetClient(), "Fibonacci", val) - .get_result(); + val = rpc::call(GetClient(), "Fibonacci", val) + .get_result(); } - return *rpc::call( + return rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; #if defined(RPC_HPP_RAPIDJSON_ENABLED) BENCHMARK("rpc.hpp (asio::tcp, rapidjson)") { - auto vec = *rpc::call>( + auto vec = rpc::call>( GetClient(), "RandInt", 5, 30, 1000) - .get_result(); + .get_result(); for (auto& val : vec) { - val = *rpc::call( + val = rpc::call( GetClient(), "Fibonacci", val) - .get_result(); + .get_result(); } - return *rpc::call( + return rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; #endif #if defined(RPC_HPP_BOOST_JSON_ENABLED) BENCHMARK("rpc.hpp (asio::tcp, bjson)") { - auto vec = *rpc::call>( + auto vec = rpc::call>( GetClient(), "RandInt", 5, 30, 1000) - .get_result(); + .get_result(); for (auto& val : vec) { - val = - *rpc::call(GetClient(), "Fibonacci", val) - .get_result(); + val = rpc::call(GetClient(), "Fibonacci", val) + .get_result(); } - return *rpc::call( + return rpc::call( GetClient(), "AverageContainer", vec) - .get_result(); + .get_result(); }; #endif } @@ -559,7 +556,7 @@ TEST_CASE("By Pointer (simple)", "[pointer][simple]") { uint64_t num = 20; test = *rpc::call(GetClient(), "FibonacciPtr", &num) - .get_arg(0); + .get_arg(); }; REQUIRE(expected == test); @@ -571,7 +568,7 @@ TEST_CASE("By Pointer (simple)", "[pointer][simple]") { uint64_t num = 20; test = *rpc::call(GetClient(), "FibonacciPtr", &num) - .get_arg(0); + .get_arg(); }; REQUIRE(expected == test); @@ -584,7 +581,7 @@ TEST_CASE("By Pointer (simple)", "[pointer][simple]") { uint64_t num = 20; test = *rpc::call(GetClient(), "FibonacciPtr", &num) - .get_arg(0); + .get_arg(); }; REQUIRE(expected == test); @@ -609,7 +606,7 @@ TEST_CASE("By Pointer (complex)", "[pointer][complex]") test = std::string( rpc::call(GetClient(), "HashComplexPtr", &cx, hash) - .get_arg(1)); + .get_arg()); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -630,7 +627,7 @@ TEST_CASE("By Pointer (complex)", "[pointer][complex]") test = std::string( rpc::call(GetClient(), "HashComplexPtr", &cx, hash) - .get_arg(1)); + .get_arg()); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -650,9 +647,12 @@ TEST_CASE("By Pointer (complex)", "[pointer][complex]") char hash[256]{}; - test = std::string( - rpc::call(GetClient(), "HashComplexPtr", &cx, hash) - .get_arg(1)); + test = std::string(rpc::call( + GetClient(), "HashComplexPtr", &cx, hash) + .get_arg + < char*, + 1) + > (); }; REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); @@ -680,16 +680,16 @@ TEST_CASE("By Pointer (many)", "[pointer][many]") const auto pack = rpc::call(GetClient(), "SquareRootPtr", &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9, &n10); - n1 = *pack.get_arg(0); - n2 = *pack.get_arg(1); - n3 = *pack.get_arg(2); - n4 = *pack.get_arg(3); - n5 = *pack.get_arg(4); - n6 = *pack.get_arg(5); - n7 = *pack.get_arg(6); - n8 = *pack.get_arg(7); - n9 = *pack.get_arg(8); - n10 = *pack.get_arg(9); + n1 = *pack.get_arg(); + n2 = *pack.get_arg(); + n3 = *pack.get_arg(); + n4 = *pack.get_arg(); + n5 = *pack.get_arg(); + n6 = *pack.get_arg(); + n7 = *pack.get_arg(); + n8 = *pack.get_arg(); + n9 = *pack.get_arg(); + n10 = *pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -714,16 +714,16 @@ TEST_CASE("By Pointer (many)", "[pointer][many]") const auto pack = rpc::call(GetClient(), "SquareRootPtr", &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9, &n10); - n1 = *pack.get_arg(0); - n2 = *pack.get_arg(1); - n3 = *pack.get_arg(2); - n4 = *pack.get_arg(3); - n5 = *pack.get_arg(4); - n6 = *pack.get_arg(5); - n7 = *pack.get_arg(6); - n8 = *pack.get_arg(7); - n9 = *pack.get_arg(8); - n10 = *pack.get_arg(9); + n1 = *pack.get_arg(); + n2 = *pack.get_arg(); + n3 = *pack.get_arg(); + n4 = *pack.get_arg(); + n5 = *pack.get_arg(); + n6 = *pack.get_arg(); + n7 = *pack.get_arg(); + n8 = *pack.get_arg(); + n9 = *pack.get_arg(); + n10 = *pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -749,16 +749,16 @@ TEST_CASE("By Pointer (many)", "[pointer][many]") const auto pack = rpc::call(GetClient(), "SquareRootPtr", &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9, &n10); - n1 = *pack.get_arg(0); - n2 = *pack.get_arg(1); - n3 = *pack.get_arg(2); - n4 = *pack.get_arg(3); - n5 = *pack.get_arg(4); - n6 = *pack.get_arg(5); - n7 = *pack.get_arg(6); - n8 = *pack.get_arg(7); - n9 = *pack.get_arg(8); - n10 = *pack.get_arg(9); + n1 = *pack.get_arg(); + n2 = *pack.get_arg(); + n3 = *pack.get_arg(); + n4 = *pack.get_arg(); + n5 = *pack.get_arg(); + n6 = *pack.get_arg(); + n7 = *pack.get_arg(); + n8 = *pack.get_arg(); + n9 = *pack.get_arg(); + n10 = *pack.get_arg(); test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; }; @@ -767,7 +767,8 @@ TEST_CASE("By Pointer (many)", "[pointer][many]") } #endif -TEST_CASE("KillServer", "[!mayfail][value][simple][cached][ref][complex][sequential][pointer][many][container]") +TEST_CASE("KillServer", + "[!mayfail][value][simple][cached][ref][complex][sequential][pointer][many][container]") { auto& client = GetClient(); diff --git a/tests/rpc.client.hpp b/tests/rpc.client.hpp index 5ea1c4fe..d1acc16b 100644 --- a/tests/rpc.client.hpp +++ b/tests/rpc.client.hpp @@ -1,7 +1,7 @@ ///@file rpc.client.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Example implementation of an RPC client class -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License diff --git a/tests/rpc.server.cpp b/tests/rpc.server.cpp index e82f67e1..0f3fad63 100644 --- a/tests/rpc.server.cpp +++ b/tests/rpc.server.cpp @@ -1,7 +1,7 @@ ///@file rpc.server.cpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Example implementation of an RPC server -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -199,6 +199,11 @@ void HashComplexPtr(const ComplexObject* const cx, char* const hashStr) } #endif +void ThrowError() +{ + throw std::runtime_error("THIS IS A TEST ERROR!"); +} + void KillServer() { RUNNING = false; @@ -492,14 +497,15 @@ void rpc::server::dispatch(typename Serial::doc_type& serial_obj) const auto func_name = serial_adapter::extract_func_name(serial_obj); RPC_ATTACH_FUNCS(PtrSum, ReadMessagePtr, WriteMessagePtr, FibonacciPtr, SquareRootPtr, - HashComplexPtr, KillServer, AddOneToEach, AddOneToEachRef, ReadMessageRef, WriteMessageRef, - ReadMessageVec, WriteMessageVec, ClearBus, FibonacciRef, SquareRootRef, RandInt, - HashComplexRef) + HashComplexPtr, KillServer, ThrowError, AddOneToEach, AddOneToEachRef, ReadMessageRef, + WriteMessageRef, ReadMessageVec, WriteMessageVec, ClearBus, FibonacciRef, SquareRootRef, + RandInt, HashComplexRef) RPC_ATTACH_CACHED_FUNCS(AddAllPtr, SimpleSum, StrLen, AddOneToEach, Fibonacci, Average, StdDev, AverageContainer, AverageContainer, HashComplex) - throw std::runtime_error("RPC error: Called function: \"" + func_name + "\" not found!"); + serial_adapter::set_err_mesg( + serial_obj, "RPC error: Called function: \"" + func_name + "\" not found!"); } #else @@ -508,13 +514,15 @@ void rpc::server::dispatch(typename Serial::doc_type& serial_obj) { const auto func_name = serial_adapter::extract_func_name(serial_obj); - RPC_ATTACH_FUNCS(KillServer, AddOneToEachRef, ReadMessageRef, WriteMessageRef, ReadMessageVec, - WriteMessageVec, ClearBus, FibonacciRef, SquareRootRef, RandInt, HashComplexRef) + RPC_ATTACH_FUNCS(KillServer, ThrowError, AddOneToEachRef, ReadMessageRef, WriteMessageRef, + ReadMessageVec, WriteMessageVec, ClearBus, FibonacciRef, SquareRootRef, RandInt, + HashComplexRef) RPC_ATTACH_CACHED_FUNCS(SimpleSum, StrLen, AddOneToEach, Fibonacci, Average, StdDev, AverageContainer, AverageContainer, HashComplex) - throw std::runtime_error("RPC error: Called function: \"" + func_name + "\" not found!"); + serial_adapter::set_err_mesg( + serial_obj, "RPC error: Called function: \"" + func_name + "\" not found!"); } #endif diff --git a/tests/rpc.test.cpp b/tests/rpc.test.cpp index 72b95230..2b34ec68 100644 --- a/tests/rpc.test.cpp +++ b/tests/rpc.test.cpp @@ -1,7 +1,7 @@ ///@file rpc.test.cpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Unit test source file for rpc.hpp -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License @@ -62,7 +62,7 @@ void TestType() { auto& client = GetClient(); auto pack = rpc::call(client, "SimpleSum", 1, 2); - REQUIRE(*pack.get_result() == 3); + REQUIRE(pack.get_result() == 3); } template<> @@ -128,7 +128,7 @@ TEST_CASE("PtrSum") int n = 12; const auto pack = rpc::call(client, "PtrSum", &n, -3); - auto* ptr = pack.get_arg(0); + auto* ptr = pack.get_arg(); REQUIRE(ptr != nullptr); REQUIRE(*ptr == 9); @@ -141,7 +141,7 @@ TEST_CASE("AddAllPtr") int myArr[] = { 2, 5, 7, 3 }; const auto pack = rpc::call(client, "AddAllPtr", myArr, 4); - REQUIRE(*pack.get_result() == 17); + REQUIRE(pack.get_result() == 17); } TEST_CASE("FibonacciPtr") @@ -150,7 +150,7 @@ TEST_CASE("FibonacciPtr") uint64_t n = 20; const auto pack = rpc::call(client, "FibonacciPtr", &n); - auto* ptr = pack.get_arg(0); + auto* ptr = pack.get_arg(); REQUIRE(ptr != nullptr); REQUIRE(*ptr == 10946ULL); @@ -174,16 +174,16 @@ TEST_CASE("SquareRootPtr") const auto pack = rpc::call( client, "SquareRootPtr", &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9, &n10); - n1 = *pack.get_arg(0); - n2 = *pack.get_arg(1); - n3 = *pack.get_arg(2); - n4 = *pack.get_arg(3); - n5 = *pack.get_arg(4); - n6 = *pack.get_arg(5); - n7 = *pack.get_arg(6); - n8 = *pack.get_arg(7); - n9 = *pack.get_arg(8); - n10 = *pack.get_arg(9); + n1 = *pack.get_arg(); + n2 = *pack.get_arg(); + n3 = *pack.get_arg(); + n4 = *pack.get_arg(); + n5 = *pack.get_arg(); + n6 = *pack.get_arg(); + n7 = *pack.get_arg(); + n8 = *pack.get_arg(); + n9 = *pack.get_arg(); + n10 = *pack.get_arg(); const auto test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; REQUIRE_THAT(test, Catch::Matchers::WithinAbs(313.2216436152, 0.001)); @@ -204,7 +204,7 @@ TEST_CASE("HashComplexPtr") char hash[256]{}; const std::string test( - rpc::call(client, "HashComplexPtr", &cx, hash).get_arg(1)); + rpc::call(client, "HashComplexPtr", &cx, hash).get_arg()); REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); } @@ -237,10 +237,10 @@ TEST_CASE("WriteMessagePtr") int numMsg = 2; const auto pack = rpc::call(client, "WriteMessagePtr", msg, &numMsg); - numMsg = *pack.get_arg(1); + numMsg = *pack.get_arg(); REQUIRE(numMsg == 2); - REQUIRE(*pack.get_result() == 0); + REQUIRE(pack.get_result() == 0); } TEST_CASE("ReadMessagePtr") @@ -251,11 +251,11 @@ TEST_CASE("ReadMessagePtr") int numMsg = 2; const auto pack = rpc::call(client, "ReadMessagePtr", msg, &numMsg); - const auto* ptr = pack.get_arg(0); - numMsg = *pack.get_arg(1); + const auto* ptr = pack.get_arg(); + numMsg = *pack.get_arg(); REQUIRE(numMsg == 2); - REQUIRE(*pack.get_result() == 0); + REQUIRE(pack.get_result() == 0); REQUIRE(ptr[0].id == 14); REQUIRE(ptr[1].id == 15); } @@ -266,7 +266,7 @@ TEST_CASE("StrLen") auto& client = GetClient(); const auto pack = rpc::call(client, "StrLen", std::string("hello, world")); - REQUIRE(*pack.get_result() == 12); + REQUIRE(pack.get_result() == 12); } TEST_CASE("AddOneToEach") @@ -275,7 +275,7 @@ TEST_CASE("AddOneToEach") const std::vector vec{ 2, 4, 6, 8 }; const auto pack = rpc::call>(client, "AddOneToEach", vec); - const auto retVec = *pack.get_result(); + const auto retVec = pack.get_result(); REQUIRE(retVec.size() == vec.size()); for (size_t i = 0; i < retVec.size(); ++i) @@ -290,7 +290,7 @@ TEST_CASE("AddOneToEachRef") std::vector vec{ 2, 4, 6, 8 }; const auto pack = rpc::call(client, "AddOneToEachRef", vec); - const auto retVec = pack.get_arg>(0); + const auto retVec = pack.get_arg, 0>(); REQUIRE(retVec.size() == vec.size()); for (size_t i = 0; i < retVec.size(); ++i) @@ -304,7 +304,7 @@ TEST_CASE("Fibonacci") constexpr uint64_t expected = 10946ULL; auto& client = GetClient(); - const auto test = *rpc::call(client, "Fibonacci", 20).get_result(); + const auto test = rpc::call(client, "Fibonacci", 20).get_result(); REQUIRE(expected == test); } @@ -314,7 +314,7 @@ TEST_CASE("FibonacciRef") auto& client = GetClient(); uint64_t num = 20ULL; - const auto test = rpc::call(client, "FibonacciRef", num).get_arg(0); + const auto test = rpc::call(client, "FibonacciRef", num).get_arg(); //REQUIRE(num == test); REQUIRE(expected == test); @@ -325,9 +325,9 @@ TEST_CASE("StdDev") constexpr double expected = 3313.695594785; auto& client = GetClient(); - const auto test = *rpc::call(client, "StdDev", 55.65, 125.325, 552.125, + const auto test = rpc::call(client, "StdDev", 55.65, 125.325, 552.125, 12.767, 2599.6, 1245.125663, 9783.49, 125.12, 553.3333333333, 2266.1) - .get_result(); + .get_result(); REQUIRE_THAT(test, Catch::Matchers::WithinRel(expected)); } @@ -352,16 +352,16 @@ TEST_CASE("SquareRootRef") rpc::call(client, "SquareRootRef", n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); // TODO: Find a way to have references updated automatically? - n1 = pack.get_arg(0); - n2 = pack.get_arg(1); - n3 = pack.get_arg(2); - n4 = pack.get_arg(3); - n5 = pack.get_arg(4); - n6 = pack.get_arg(5); - n7 = pack.get_arg(6); - n8 = pack.get_arg(7); - n9 = pack.get_arg(8); - n10 = pack.get_arg(9); + n1 = pack.get_arg(); + n2 = pack.get_arg(); + n3 = pack.get_arg(); + n4 = pack.get_arg(); + n5 = pack.get_arg(); + n6 = pack.get_arg(); + n7 = pack.get_arg(); + n8 = pack.get_arg(); + n9 = pack.get_arg(); + n10 = pack.get_arg(); const auto test = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10; @@ -377,7 +377,7 @@ TEST_CASE("AverageContainer") 125.12, 553.3333333333, 2266.1 }; const auto test = - *rpc::call(client, "AverageContainer", vec).get_result(); + rpc::call(client, "AverageContainer", vec).get_result(); REQUIRE_THAT(test, Catch::Matchers::WithinAbs(expected, 0.001)); } @@ -394,8 +394,7 @@ TEST_CASE("HashComplex") cx.name = "Franklin D. Roosevelt"; cx.vals = { 0, 1, 4, 6, 7, 8, 11, 15, 17, 22, 25, 26 }; - const auto test = - *rpc::call(client, "HashComplex", cx).get_result(); + const auto test = rpc::call(client, "HashComplex", cx).get_result(); REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); } @@ -415,11 +414,35 @@ TEST_CASE("HashComplexRef") std::string test; // TODO: Find a way to have references updated automatically? - test = rpc::call(client, "HashComplexRef", cx, test).get_arg(1); + test = rpc::call(client, "HashComplexRef", cx, test).get_arg(); REQUIRE_THAT(expected, Catch::Matchers::Equals(test)); } +TEST_CASE("function not found") +{ + auto& client = GetClient(); + + const auto exp = [&client]() { + [[maybe_unused]] auto x = rpc::call(client, "FUNC_WHICH_DOES_NOT_EXIST").get_result(); + }; + + REQUIRE_THROWS_WITH(exp(), + Catch::Matchers::Equals( + "RPC error: Called function: \"FUNC_WHICH_DOES_NOT_EXIST\" not found!")); +} + +TEST_CASE("ThrowError") +{ + auto& client = GetClient(); + + const auto exp = [&client]() { + [[maybe_unused]] auto x = rpc::call(client, "ThrowError").get_result(); + }; + + REQUIRE_THROWS_WITH(exp(), "THIS IS A TEST ERROR!"); +} + TEST_CASE("KillServer", "[!mayfail]") { auto& client = GetClient(); diff --git a/tests/test_structs.hpp b/tests/test_structs.hpp index 377b1026..fe51b0cc 100644 --- a/tests/test_structs.hpp +++ b/tests/test_structs.hpp @@ -1,7 +1,7 @@ ///@file test_structs.hpp ///@author Jackson Harmer (jharmer95@gmail.com) ///@brief Structures/classes for use with rpc.hpp unit tests -///@version 0.3.2 +///@version 0.3.3 /// ///@copyright ///BSD 3-Clause License