1 #pragma once
2
3 #ifndef RESPONSE_H_MVRZEKPX
4 #define RESPONSE_H_MVRZEKPX
5
6 #include "rpc/detail/log.h"
7 #include "rpc/detail/make_unique.h"
8 #include "rpc/msgpack.hpp"
9 #include "rpc/config.h"
10
11 namespace rpc {
12 namespace detail {
13
14 //! \brief Represents a response and creates a msgpack to be sent back
15 //! as per the msgpack-rpc spec.
16 class response {
17 public:
18 //! \brief Creates a response that represents a normal return value.
19 //! \param id The sequence id (as per protocol).
20 //! \param result The return value to store in the response.
21 //! \tparam T Any msgpack-able type.
22 //! \note If there is both an error and result in the response,
23 //! the result will be discarded while packing the data.
24 template <typename T> static response make_result(uint32_t id, T &&result);
25
26 //! \brief Creates a response that represents an error.
27 //! \param id The sequence id (as per protocol).
28 //! \param error The error value to store in the response.
29 //! \tparam T Any msgpack-able type.
30 template <typename T> static response make_error(uint32_t id, T &&error);
31
32
33 //! \brief Constructs a response from RPCLIB_MSGPACK::object (useful when
34 //! reading a response from a stream).
35 response(RPCLIB_MSGPACK::object_handle o);
36
37 //! \brief Gets the response data as a RPCLIB_MSGPACK::sbuffer.
38 RPCLIB_MSGPACK::sbuffer get_data() const;
39
40 //! \brief Moves the specified object_handle into the response
41 //! as a result.
42 //! \param r The result to capture.
43 void capture_result(RPCLIB_MSGPACK::object_handle &r);
44
45 //! \brief Moves the specified object_handle into the response as an error.
46 //! \param e The error to capture.
47 void capture_error(RPCLIB_MSGPACK::object_handle &e);
48
49 //! \brief Returns the call id/index used to identify which call
50 //! this response corresponds to.
51 uint32_t get_id() const;
52
53 //! \brief Returns the error object stored in the response. Can
54 //! be empty.
55 std::shared_ptr<RPCLIB_MSGPACK::object_handle> get_error() const;
56
57 //! \brief Returns the result stored in the response. Can be empty.
58 std::shared_ptr<RPCLIB_MSGPACK::object_handle> get_result() const;
59
60 //! \brief Gets an empty response which means "no response" (not to be
61 //! confused with void return, i.e. this means literally
62 //! "don't write the response to the socket")
63 static response empty();
64
65 //! \brief If true, this response is empty (\see empty())
66 bool is_empty() const;
67
68 //! \brief The type of a response, according to the msgpack-rpc spec
69 using response_type =
70 std::tuple<uint32_t, uint32_t, RPCLIB_MSGPACK::object, RPCLIB_MSGPACK::object>;
71
72 private:
73 //! \brief Default constructor for responses.
74 response();
75
76 uint32_t id_;
77 // I really wish to avoid shared_ptr here but at this point asio does not
78 // work with move-only handlers in post() and I need to capture responses
79 // in lambdas.
80 std::shared_ptr<RPCLIB_MSGPACK::object_handle> error_;
81 std::shared_ptr<RPCLIB_MSGPACK::object_handle> result_;
82 bool empty_;
83 RPCLIB_CREATE_LOG_CHANNEL(response)
84 };
85
86 template <typename T>
make_result(uint32_t id,T && result)87 inline response response::make_result(uint32_t id, T &&result) {
88 auto z = rpc::detail::make_unique<RPCLIB_MSGPACK::zone>();
89 RPCLIB_MSGPACK::object o(std::forward<T>(result), *z);
90 response inst;
91 inst.id_ = id;
92 inst.result_ = std::make_shared<RPCLIB_MSGPACK::object_handle>(o, std::move(z));
93 return inst;
94 }
95
96 template <>
97 inline response
make_result(uint32_t id,std::unique_ptr<RPCLIB_MSGPACK::object_handle> && r)98 response::make_result(uint32_t id, std::unique_ptr<RPCLIB_MSGPACK::object_handle> &&r) {
99 response inst;
100 inst.id_ = id;
101 inst.result_ = std::move(r);
102 return inst;
103 }
104
105 template <typename T>
make_error(uint32_t id,T && error)106 inline response response::make_error(uint32_t id, T &&error) {
107 auto z = rpc::detail::make_unique<RPCLIB_MSGPACK::zone>();
108 RPCLIB_MSGPACK::object o(std::forward<T>(error), *z);
109 response inst;
110 inst.id_ = id;
111 inst.error_ = std::make_shared<RPCLIB_MSGPACK::object_handle>(o, std::move(z));
112 return inst;
113 }
114
115 } /* detail */
116
117 } /* rpc */
118
119 #endif /* end of include guard: RESPONSE_H_MVRZEKPX */
120