xref: /aosp_15_r20/external/cronet/base/types/expected_macros.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TYPES_EXPECTED_MACROS_H_
6 #define BASE_TYPES_EXPECTED_MACROS_H_
7 
8 #include <functional>
9 #include <string_view>
10 #include <type_traits>
11 #include <utility>
12 
13 #include "base/compiler_specific.h"
14 #include "base/macros/concat.h"
15 #include "base/macros/remove_parens.h"
16 #include "base/macros/uniquify.h"
17 #include "base/memory/raw_ptr_exclusion.h"
18 #include "base/types/expected.h"
19 
20 // Executes an expression `rexpr` that returns a `base::expected<T, E>`. If the
21 // result is an error, causes the calling function to return. If no additional
22 // arguments are given, the function return value is the `E` returned by
23 // `rexpr`. Otherwise, the additional arguments are treated as an invocable that
24 // expects an E as its last argument and returns some type (including `void`)
25 // convertible to the function's return type; that is, the function returns the
26 // result of `std::invoke(..., E)`.
27 //
28 // This works with move-only types and can be used in functions that return
29 // either an `E` directly or a `base::expected<U, E>`, without needing to
30 // explicitly wrap the return in `base::unexpected`.
31 //
32 // # Interface
33 //
34 // `RETURN_IF_ERROR(rexpr, ...);`
35 //
36 // # Examples
37 //
38 // Use with no additional arguments:
39 // ```
40 //   SomeErrorCode Foo() {
41 //     RETURN_IF_ERROR(Function(args...));
42 //     return SomeErrorCode::kOK;
43 //   }
44 // ```
45 // ```
46 //   base::expected<int, SomeErrorCode> Bar() {
47 //     RETURN_IF_ERROR(Function(args...));
48 //     RETURN_IF_ERROR(obj.Method(args...));
49 //     return 17;
50 //   }
51 // ```
52 //
53 // Adjusting the returned error:
54 // ```
55 //   RETURN_IF_ERROR(TryProcessing(query),
56 //                   [](const auto& e) {
57 //                     return base::StrCat({e, " while processing query"});
58 //                   });
59 // ```
60 //
61 // Returning a different kind of error:
62 // ```
63 //   RETURN_IF_ERROR(TryProcessing(query),
64 //                   [](auto) { return SomeErrorCode::kFail); });
65 // ```
66 //
67 // Returning void:
68 // ```
69 //   RETURN_IF_ERROR(TryProcessing(query), [](auto) {});
70 // ```
71 // ```
72 //   RETURN_IF_ERROR(TryProcessing(query),
73 //                   [](auto) { LOG(WARNING) << "Uh oh"; }());
74 // ```
75 //
76 // Automatic conversion to `base::expected<U, E>`:
77 // ```
78 //   base::expected<int, SomeErrorCode> Foo() {
79 //     RETURN_IF_ERROR(TryProcessing(query),
80 //                     [](auto) { return SomeErrorCode::kFail); });
81 //     return 17;
82 //   }
83 // ```
84 //
85 // Passing the error to a static/global handler:
86 // ```
87 //   RETURN_IF_ERROR(TryProcessing(query), &FailureHandler);
88 // ```
89 //
90 // Passing the error to a handler member function:
91 // ```
92 //   RETURN_IF_ERROR(TryProcessing(query), &MyClass::FailureHandler, this);
93 // ```
94 #define RETURN_IF_ERROR(rexpr, ...) \
95   BASE_INTERNAL_EXPECTED_RETURN_IF_ERROR_IMPL(return, rexpr, __VA_ARGS__)
96 
97 // Executes an expression `rexpr` that returns a `base::expected<T, E>`. If the
98 // result is an expected value, moves the `T` into whatever `lhs` defines/refers
99 // to; otherwise, behaves like RETURN_IF_ERROR() above. Avoid side effects in
100 // `lhs`, as it will not be evaluated in the error case.
101 //
102 // # Interface
103 //
104 // `ASSIGN_OR_RETURN(lhs, rexpr, ...);`
105 //
106 // WARNING: If `lhs` is parenthesized, the parentheses are removed; for this
107 //          reason, `lhs` may not contain a ternary (`?:`). See examples for
108 //          motivation.
109 //
110 // WARNING: Expands into multiple statements; cannot be used in a single
111 //          statement (e.g. as the body of an `if` statement without `{}`)!
112 //
113 // # Examples
114 //
115 // Declaring and initializing a new variable (ValueType can be anything that can
116 // be initialized with assignment):
117 // ```
118 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(arg));
119 // ```
120 //
121 // Assigning to an existing variable:
122 // ```
123 //   ValueType value;
124 //   ASSIGN_OR_RETURN(value, MaybeGetValue(arg));
125 // ```
126 //
127 // Initializing a `std::unique_ptr`:
128 // ```
129 //   ASSIGN_OR_RETURN(std::unique_ptr<T> ptr, MaybeGetPtr(arg));
130 // ```
131 //
132 // Initializing a map. Because of C++ preprocessor limitations, the type used in
133 // `ASSIGN_OR_RETURN` cannot contain commas, so wrap `lhs` in parentheses:
134 // ```
135 //   ASSIGN_OR_RETURN((flat_map<Foo, Bar> my_map), GetMap());
136 // ```
137 // Or use `auto` if the type is obvious enough:
138 // ```
139 //   ASSIGN_OR_RETURN(auto code_widget, GetCodeWidget());
140 // ```
141 //
142 // Assigning to structured bindings. The same situation with comma as above, so
143 // wrap `lhs` in parentheses:
144 // ```
145 //   ASSIGN_OR_RETURN((auto [first, second]), GetPair());
146 // ```
147 //
148 // Attempting to assign to a ternary will not compile:
149 // ```
150 //   ASSIGN_OR_RETURN((cond ? a : b), MaybeGetValue(arg));  // DOES NOT COMPILE
151 // ```
152 //
153 // Adjusting the returned error:
154 // ```
155 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query),
156 //                    [](const auto& e) {
157 //                      return base::StrCat({e, " while getting value"});
158 //                    });
159 // ```
160 //
161 // Returning a different kind of error:
162 // ```
163 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query),
164 //                    [](auto) { return SomeErrorCode::kFail); });
165 // ```
166 //
167 // Returning void:
168 // ```
169 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query), [](auto) {});
170 // ```
171 // ```
172 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query),
173 //                    [](auto) { LOG(WARNING) << "Uh oh"; }());
174 // ```
175 //
176 // Automatic conversion to `base::expected<U, E>`:
177 // ```
178 //   base::expected<int, SomeErrorCode> Foo() {
179 //     ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query),
180 //                      [](auto) { return SomeErrorCode::kFail); });
181 //     return 17;
182 //   }
183 // ```
184 //
185 // Passing the error to a static/global handler:
186 // ```
187 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query), &FailureHandler);
188 // ```
189 //
190 // Passing the error to a handler member function:
191 // ```
192 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query),
193 //                    &MyClass::FailureHandler, this);
194 // ```
195 #define ASSIGN_OR_RETURN(lhs, rexpr, ...) \
196   BASE_INTERNAL_EXPECTED_ASSIGN_OR_RETURN_IMPL(return, lhs, rexpr, __VA_ARGS__)
197 
198 namespace base::internal {
199 
200 // =================================================================
201 // == Implementation details, do not rely on anything below here. ==
202 // =================================================================
203 
204 // Helper object to allow returning some `E` from a method either directly or in
205 // the error of an `expected<T, E>`. Supports move-only `E`, as well as `void`.
206 //
207 // In order to support `void` return types, `UnexpectedDeducer` is not
208 // constructed directly from an `E`, but from a lambda that returns `E`; and
209 // callers must return `Ret()` rather than returning the deducer itself. Using
210 // both these indirections allows consistent invocation from macros.
211 template <typename Lambda, typename E = std::invoke_result_t<Lambda&&>>
212 class UnexpectedDeducer {
213  public:
UnexpectedDeducer(Lambda && lambda)214   constexpr explicit UnexpectedDeducer(Lambda&& lambda) noexcept
215       : lambda_(std::move(lambda)) {}
216 
decltype(auto)217   constexpr decltype(auto) Ret() && noexcept {
218     if constexpr (std::is_void_v<E>) {
219       std::move(lambda_)();
220     } else {
221       return std::move(*this);
222     }
223   }
224 
225   // Allow implicit conversion from `Ret()` to either `expected<T, E>` (for
226   // arbitrary `T`) or `E`.
227   template <typename T>
228   // NOLINTNEXTLINE(google-explicit-constructor)
229   constexpr operator expected<T, E>() && noexcept {
230     return expected<T, E>(unexpect, std::move(lambda_)());
231   }
232   // NOLINTNEXTLINE(google-explicit-constructor)
E()233   constexpr operator E() && noexcept { return std::move(lambda_)(); }
234 
235  private:
236   // RAW_PTR_EXCLUSION: Not intended to handle &&-qualified members.
237   // `UnexpectedDeducer` is a short-lived temporary and tries to minimize
238   // copying and other overhead; using raw_ptr/ref goes against this design
239   // without adding meaningful safety.
240   RAW_PTR_EXCLUSION Lambda&& lambda_;
241 };
242 
243 // Deduce the type of the lambda automatically so callers don't need to spell
244 // things twice (or use temps) and use decltype.
245 template <typename Lambda>
246 UnexpectedDeducer(Lambda) -> UnexpectedDeducer<Lambda>;
247 
248 }  // namespace base::internal
249 
250 #define BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, name, return_keyword, \
251                                     error_expr)                            \
252   decltype(auto) expected = (rexpr);                                       \
253   {                                                                        \
254     static_assert(base::internal::IsExpected<decltype(expected)>,          \
255                   #name " should only be used with base::expected<>");     \
256   }                                                                        \
257   if (UNLIKELY(!expected.has_value())) {                                   \
258     return_keyword base::internal::UnexpectedDeducer([&] {                 \
259       return error_expr;                                                   \
260     }).Ret();                                                              \
261   }
262 
263 #define BASE_INTERNAL_EXPECTED_RETURN_IF_ERROR(expected, rexpr,            \
264                                                return_keyword, error_expr) \
265   do {                                                                     \
266     BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, RETURN_IF_ERROR,          \
267                                 return_keyword, error_expr);               \
268   } while (false)
269 
270 #define BASE_INTERNAL_EXPECTED_ASSIGN_OR_RETURN(                            \
271     expected, rexpr, return_keyword, error_expr, lhs)                       \
272   BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, ASSIGN_OR_RETURN,            \
273                               return_keyword, error_expr);                  \
274   {                                                                         \
275     static_assert(#lhs[0] != '(' || #lhs[sizeof #lhs - 2] != ')' ||         \
276                       std::string_view(#lhs).rfind('?', sizeof #lhs - 2) == \
277                           base::StringPiece::npos,                          \
278                   "Identified possible ternary in `lhs`; avoid passing "    \
279                   "parenthesized expressions containing '?' to the first "  \
280                   "argument of ASSIGN_OR_RETURN()");                        \
281   }                                                                         \
282   BASE_REMOVE_PARENS(lhs) = std::move(expected).value();
283 
284 #define BASE_INTERNAL_EXPECTED_PASS_ARGS(func, ...) func(__VA_ARGS__)
285 
286 // These are necessary to avoid mismatched parens inside __VA_OPT__() below.
287 #define BASE_INTERNAL_EXPECTED_BEGIN_INVOKE std::invoke(
288 #define BASE_INTERNAL_EXPECTED_END_INVOKE )
289 
290 #define BASE_INTERNAL_EXPECTED_ARGS(temp_name, return_keyword, rexpr, ...) \
291   temp_name, rexpr, return_keyword,                                        \
292       (__VA_OPT__(BASE_INTERNAL_EXPECTED_BEGIN_INVOKE)                     \
293            __VA_ARGS__ __VA_OPT__(, ) std::move(temp_name)                 \
294                .error() __VA_OPT__(BASE_INTERNAL_EXPECTED_END_INVOKE))
295 
296 #define BASE_INTERNAL_EXPECTED_RETURN_IF_ERROR_IMPL(return_keyword, rexpr, \
297                                                     ...)                   \
298   BASE_INTERNAL_EXPECTED_PASS_ARGS(                                        \
299       BASE_INTERNAL_EXPECTED_RETURN_IF_ERROR,                              \
300       BASE_INTERNAL_EXPECTED_ARGS(BASE_UNIQUIFY(_expected_value),          \
301                                   return_keyword, rexpr, __VA_ARGS__))
302 
303 #define BASE_INTERNAL_EXPECTED_ASSIGN_OR_RETURN_IMPL(return_keyword, lhs, \
304                                                      rexpr, ...)          \
305   BASE_INTERNAL_EXPECTED_PASS_ARGS(                                       \
306       BASE_INTERNAL_EXPECTED_ASSIGN_OR_RETURN,                            \
307       BASE_INTERNAL_EXPECTED_ARGS(BASE_UNIQUIFY(_expected_value),         \
308                                   return_keyword, rexpr, __VA_ARGS__),    \
309       lhs)
310 
311 #endif  // BASE_TYPES_EXPECTED_MACROS_H_
312