1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_STATUS_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_STATUS_H
17
18 #include <grpc/support/port_platform.h>
19
20 #include <utility>
21
22 #include "absl/log/check.h"
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25
26 // Helpers for dealing with absl::Status/StatusOr generically
27
28 namespace grpc_core {
29 namespace promise_detail {
30
31 // Convert with a move the input status to an absl::Status.
32 template <typename T>
IntoStatus(absl::StatusOr<T> * status)33 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline absl::Status IntoStatus(
34 absl::StatusOr<T>* status) {
35 return std::move(status->status());
36 }
37
38 // Convert with a move the input status to an absl::Status.
IntoStatus(absl::Status * status)39 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline absl::Status IntoStatus(
40 absl::Status* status) {
41 return std::move(*status);
42 }
43
44 } // namespace promise_detail
45
46 // Return true if the status represented by the argument is ok, false if not.
47 // By implementing this function for other, non-absl::Status types, those types
48 // can participate in TrySeq as result types that affect control flow.
IsStatusOk(const absl::Status & status)49 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(
50 const absl::Status& status) {
51 return status.ok();
52 }
53
54 template <typename T>
IsStatusOk(const absl::StatusOr<T> & status)55 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(
56 const absl::StatusOr<T>& status) {
57 return status.ok();
58 }
59
60 template <typename To, typename From, typename SfinaeVoid = void>
61 struct StatusCastImpl;
62
63 template <typename To>
64 struct StatusCastImpl<To, To> {
65 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static To Cast(To&& t) {
66 return std::move(t);
67 }
68 };
69
70 template <typename To>
71 struct StatusCastImpl<To, const To&> {
72 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static To Cast(const To& t) { return t; }
73 };
74
75 template <typename T>
76 struct StatusCastImpl<absl::Status, absl::StatusOr<T>> {
77 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
78 absl::StatusOr<T>&& t) {
79 return std::move(t.status());
80 }
81 };
82
83 template <typename T>
84 struct StatusCastImpl<absl::Status, absl::StatusOr<T>&> {
85 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
86 const absl::StatusOr<T>& t) {
87 return t.status();
88 }
89 };
90
91 template <typename T>
92 struct StatusCastImpl<absl::Status, const absl::StatusOr<T>&> {
93 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
94 const absl::StatusOr<T>& t) {
95 return t.status();
96 }
97 };
98
99 // StatusCast<> allows casting from one status-bearing type to another,
100 // regardless of whether the status indicates success or failure.
101 // This means that we can go from StatusOr to Status safely, but not in the
102 // opposite direction.
103 // For cases where the status is guaranteed to be a failure (and hence not
104 // needing to preserve values) see FailureStatusCast<> below.
105 template <typename To, typename From>
106 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline To StatusCast(From&& from) {
107 return StatusCastImpl<To, From>::Cast(std::forward<From>(from));
108 }
109
110 template <typename To, typename From, typename SfinaeVoid = void>
111 struct FailureStatusCastImpl : public StatusCastImpl<To, From> {};
112
113 template <typename T>
114 struct FailureStatusCastImpl<absl::StatusOr<T>, absl::Status> {
115 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
116 absl::Status&& t) {
117 return std::move(t);
118 }
119 };
120
121 template <typename T>
122 struct FailureStatusCastImpl<absl::StatusOr<T>, const absl::Status&> {
123 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
124 const absl::Status& t) {
125 return t;
126 }
127 };
128
129 template <typename To, typename From>
130 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline To FailureStatusCast(From&& from) {
131 DCHECK(!IsStatusOk(from));
132 return FailureStatusCastImpl<To, From>::Cast(std::forward<From>(from));
133 }
134
135 } // namespace grpc_core
136
137 #endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_STATUS_H
138