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