userver: userver/ugrpc/server/result.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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) : result_{std::move(response)} {}
29
30 /// Construct from `grpc::Status`, only error status is allowed.
31 /*implicit*/ Result(grpc::Status&& status) : result_{std::move(status)} {
32 UINVARIANT(!GetErrorStatus().ok(), "Only error status is allowed, for OK status a response should be provided");
33 }
34
35 /// Construct from `grpc::Status`, only error status is allowed.
36 /*implicit*/ Result(const grpc::Status& status) : result_{status} {
37 UINVARIANT(!GetErrorStatus().ok(), "Only error status is allowed, for OK status a response should be provided");
38 }
39
40 /// @returns `true` iff the `Result` contains `Response`, as opposed to an error status.
41 bool IsSuccess() const { return std::holds_alternative<Response>(result_); }
42
43 /// @returns the contained error status.
44 /// @pre `IsSuccess() == false`.
45 grpc::Status&& ExtractErrorStatus() {
46 UINVARIANT(!IsSuccess(), "ExtractErrorStatus is only allowed in case of error status");
47 return std::move(std::get<grpc::Status>(result_));
48 }
49
50 /// @returns the contained error status.
51 /// @pre `IsSuccess() == false`.
52 const grpc::Status& GetErrorStatus() const {
53 UINVARIANT(!IsSuccess(), "GetErrorStatus is only allowed in case of error status");
54 return std::get<grpc::Status>(result_);
55 }
56
57 /// @returns the contained response.
58 /// @pre `IsSuccess() == true`.
59 Response&& ExtractResponse() {
60 UINVARIANT(IsSuccess(), "ExtractResponse is only allowed in case of OK status");
61 return std::get<Response>(std::move(result_));
62 }
63
64 /// @returns the contained error status.
65 /// @pre `IsSuccess() == true`.
66 const Response& GetResponse() const {
67 UINVARIANT(IsSuccess(), "GetResponse is only allowed in case of OK status");
68 return std::get<Response>(result_);
69 }
70
71private:
72 std::variant<Response, grpc::Status> result_;
73};
74
75/// @brief Special result type for server-streaming service handlers.
76///
77/// Provides a way to return one of:
78/// 1. `grpc::Status::OK`;
79/// 2. error `grpc::Status`;
80/// 3. last response + `grpc::Status::OK`, sent in a single batch.
81///
82/// For non-server-streaming RPCs, see @ref ugrpc::server::Result.
83template <typename Response>
84class StreamingResult final {
85public:
86 /// Construct from `grpc::Status` (which can be `OK` or an error status).
87 /*implicit*/ StreamingResult(grpc::Status&& status) : status_{std::move(status)} {}
88
89 /// Construct from `grpc::Status` (which can be `OK` or an error status).
90 /*implicit*/ StreamingResult(const grpc::Status& status) : status_{status} {}
91
92 /// Construct from last response. Allows to send last response and `OK` status coalesced in a single batch.
93 /*implicit*/ StreamingResult(Response&& last_response) : last_response_(std::move(last_response)) {}
94
95 /// @returns `true` iff the `StreamingResult` contains `OK` status, possibly with a last response.
96 bool IsSuccess() const { return status_.ok(); }
97
98 /// @returns the contained status, which can be `OK` or an error status.
99 grpc::Status&& ExtractStatus() { return std::move(status_); }
100
101 /// @returns the contained status, which can be `OK` or an error status.
102 const grpc::Status& GetStatus() const { return status_; }
103
104 /// @returns `true` iff the `StreamingResult` contains last response, which implies `OK` status.
105 bool HasLastResponse() const { return last_response_.has_value(); }
106
107 /// @returns the contained last response.
108 /// @pre `HasLastResponse() == true`.
109 Response&& ExtractLastResponse() {
110 UINVARIANT(HasLastResponse(), "There is no last response in the StreamingResult");
111 return std::move(last_response_).value();
112 }
113
114 /// @returns the contained last response.
115 /// @pre `HasLastResponse() == true`.
116 const Response& GetLastResponse() const {
117 UINVARIANT(HasLastResponse(), "There is no last response in the StreamingResult");
118 return last_response_.value();
119 }
120
121private:
122 std::optional<Response> last_response_;
123 grpc::Status status_{grpc::Status::OK};
124};
125
126} // namespace ugrpc::server
127
128USERVER_NAMESPACE_END