userver: userver/ugrpc/server/result.hpp Source File
Loading...
Searching...
No Matches
result.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/ugrpc/server/result.hpp
4/// @brief @copybrief ugrpc::server::Result
5
6#include <optional>
7#include <variant>
8
9#include <grpcpp/support/status.h>
10
11#include <userver/utils/assert.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace ugrpc::server {
16
17/// @brief Result type for service handlers (non server-streaming).
18///
19/// Provides a way to return one of:
20/// 1. `Response` + `grpc::Status::OK`;
21/// 2. error `grpc::Status`.
22///
23/// For server-streaming RPCs, see @ref ugrpc::server::StreamingResult.
24template <typename Response>
25class Result {
26public:
27 /// Construct from `Response`, implies `OK` status.
28 /*implicit*/ Result(Response&& response)
29 : result_{std::move(response)}
30 {}
31
32 /// Construct from `grpc::Status`, only error status is allowed.
33 /*implicit*/ Result(grpc::Status&& status)
34 : result_{std::move(status)}
35 {
36 UINVARIANT(!GetErrorStatus().ok(), "Only error status is allowed, for OK status a response should be provided");
37 }
38
39 /// Construct from `grpc::Status`, only error status is allowed.
40 /*implicit*/ Result(const grpc::Status& status)
41 : result_{status}
42 {
43 UINVARIANT(!GetErrorStatus().ok(), "Only error status is allowed, for OK status a response should be provided");
44 }
45
46 /// @returns `true` if the `Result` contains `Response`, as opposed to an error status.
47 bool IsSuccess() const { return std::holds_alternative<Response>(result_); }
48
49 /// @returns the contained error status.
50 /// @pre `IsSuccess() == false`.
51 grpc::Status&& ExtractErrorStatus() {
52 UINVARIANT(!IsSuccess(), "ExtractErrorStatus is only allowed in case of error status");
53 return std::move(std::get<grpc::Status>(result_));
54 }
55
56 /// @returns the contained error status.
57 /// @pre `IsSuccess() == false`.
58 const grpc::Status& GetErrorStatus() const {
59 UINVARIANT(!IsSuccess(), "GetErrorStatus is only allowed in case of error status");
60 return std::get<grpc::Status>(result_);
61 }
62
63 /// @returns the contained response.
64 /// @pre `IsSuccess() == true`.
65 Response&& ExtractResponse() {
66 UINVARIANT(IsSuccess(), "ExtractResponse is only allowed in case of OK status");
67 return std::get<Response>(std::move(result_));
68 }
69
70 /// @returns the contained error status.
71 /// @pre `IsSuccess() == true`.
72 const Response& GetResponse() const {
73 UINVARIANT(IsSuccess(), "GetResponse is only allowed in case of OK status");
74 return std::get<Response>(result_);
75 }
76
77private:
78 std::variant<Response, grpc::Status> result_;
79};
80
81/// @brief Special result type for server-streaming service handlers.
82///
83/// Provides a way to return one of:
84/// 1. `grpc::Status::OK`;
85/// 2. error `grpc::Status`;
86/// 3. last response + `grpc::Status::OK`, sent in a single batch.
87///
88/// For non-server-streaming RPCs, see @ref ugrpc::server::Result.
89template <typename Response>
90class StreamingResult final {
91public:
92 /// Construct from `grpc::Status` (which can be `OK` or an error status).
93 /*implicit*/ StreamingResult(grpc::Status&& status)
94 : status_{std::move(status)}
95 {}
96
97 /// Construct from `grpc::Status` (which can be `OK` or an error status).
98 /*implicit*/ StreamingResult(const grpc::Status& status)
99 : status_{status}
100 {}
101
102 /// Construct from last response. Allows to send last response and `OK` status coalesced in a single batch.
103 /*implicit*/ StreamingResult(Response&& last_response)
104 : last_response_(std::move(last_response))
105 {}
106
107 /// @returns `true` if the `StreamingResult` contains `OK` status, possibly with a last response.
108 bool IsSuccess() const { return status_.ok(); }
109
110 /// @returns the contained status, which can be `OK` or an error status.
111 grpc::Status&& ExtractStatus() { return std::move(status_); }
112
113 /// @returns the contained status, which can be `OK` or an error status.
114 const grpc::Status& GetStatus() const { return status_; }
115
116 /// @returns `true` if the `StreamingResult` contains last response, which implies `OK` status.
117 bool HasLastResponse() const { return last_response_.has_value(); }
118
119 /// @returns the contained last response.
120 /// @pre `HasLastResponse() == true`.
121 Response&& ExtractLastResponse() {
122 UINVARIANT(HasLastResponse(), "There is no last response in the StreamingResult");
123 return std::move(last_response_).value();
124 }
125
126 /// @returns the contained last response.
127 /// @pre `HasLastResponse() == true`.
128 const Response& GetLastResponse() const {
129 UINVARIANT(HasLastResponse(), "There is no last response in the StreamingResult");
130 return last_response_.value();
131 }
132
133private:
134 std::optional<Response> last_response_;
135 grpc::Status status_{grpc::Status::OK};
136};
137
138} // namespace ugrpc::server
139
140USERVER_NAMESPACE_END