#pragma once #ifndef RESPONSE_H_MVRZEKPX #define RESPONSE_H_MVRZEKPX #include "rpc/detail/log.h" #include "rpc/detail/make_unique.h" #include "rpc/msgpack.hpp" #include "rpc/config.h" namespace rpc { namespace detail { //! \brief Represents a response and creates a msgpack to be sent back //! as per the msgpack-rpc spec. class response { public: //! \brief Creates a response that represents a normal return value. //! \param id The sequence id (as per protocol). //! \param result The return value to store in the response. //! \tparam T Any msgpack-able type. //! \note If there is both an error and result in the response, //! the result will be discarded while packing the data. template static response make_result(uint32_t id, T &&result); //! \brief Creates a response that represents an error. //! \param id The sequence id (as per protocol). //! \param error The error value to store in the response. //! \tparam T Any msgpack-able type. template static response make_error(uint32_t id, T &&error); //! \brief Constructs a response from RPCLIB_MSGPACK::object (useful when //! reading a response from a stream). response(RPCLIB_MSGPACK::object_handle o); //! \brief Gets the response data as a RPCLIB_MSGPACK::sbuffer. RPCLIB_MSGPACK::sbuffer get_data() const; //! \brief Moves the specified object_handle into the response //! as a result. //! \param r The result to capture. void capture_result(RPCLIB_MSGPACK::object_handle &r); //! \brief Moves the specified object_handle into the response as an error. //! \param e The error to capture. void capture_error(RPCLIB_MSGPACK::object_handle &e); //! \brief Returns the call id/index used to identify which call //! this response corresponds to. uint32_t get_id() const; //! \brief Returns the error object stored in the response. Can //! be empty. std::shared_ptr get_error() const; //! \brief Returns the result stored in the response. Can be empty. std::shared_ptr get_result() const; //! \brief Gets an empty response which means "no response" (not to be //! confused with void return, i.e. this means literally //! "don't write the response to the socket") static response empty(); //! \brief If true, this response is empty (\see empty()) bool is_empty() const; //! \brief The type of a response, according to the msgpack-rpc spec using response_type = std::tuple; private: //! \brief Default constructor for responses. response(); uint32_t id_; // I really wish to avoid shared_ptr here but at this point asio does not // work with move-only handlers in post() and I need to capture responses // in lambdas. std::shared_ptr error_; std::shared_ptr result_; bool empty_; RPCLIB_CREATE_LOG_CHANNEL(response) }; template inline response response::make_result(uint32_t id, T &&result) { auto z = rpc::detail::make_unique(); RPCLIB_MSGPACK::object o(std::forward(result), *z); response inst; inst.id_ = id; inst.result_ = std::make_shared(o, std::move(z)); return inst; } template <> inline response response::make_result(uint32_t id, std::unique_ptr &&r) { response inst; inst.id_ = id; inst.result_ = std::move(r); return inst; } template inline response response::make_error(uint32_t id, T &&error) { auto z = rpc::detail::make_unique(); RPCLIB_MSGPACK::object o(std::forward(error), *z); response inst; inst.id_ = id; inst.error_ = std::make_shared(o, std::move(z)); return inst; } } /* detail */ } /* rpc */ #endif /* end of include guard: RESPONSE_H_MVRZEKPX */