1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_STATUS_MACROS_H_
6 #define CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_STATUS_MACROS_H_
7 
8 #include "chrome/browser/policy/messaging_layer/util/status.h"
9 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
10 
11 namespace reporting {
12 
13 // Run a command that returns a Status.  If the called code returns an
14 // error status, return that status up out of this method too.
15 //
16 // Example:
17 //   RETURN_IF_ERROR(DoThings(4));
18 #define RETURN_IF_ERROR(expr)                                                \
19   do {                                                                       \
20     /* Using _status below to avoid capture problems if expr is "status". */ \
21     const ::reporting::Status _status = (expr);                              \
22     if (__builtin_expect(!_status.ok(), 0))                                  \
23       return _status;                                                        \
24   } while (0)
25 
26 // Internal helper for concatenating macro values.
27 #define STATUS_MACROS_CONCAT_NAME_INNER(x, y) x##y
28 #define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y)
29 
30 #define ASSIGN_OR_RETURN_IMPL(result, lhs, rexpr) \
31   auto result = rexpr;                            \
32   if (__builtin_expect(!result.ok(), 0)) {        \
33     return result.status();                       \
34   }                                               \
35   lhs = std::move(result).ValueOrDie()
36 
37 // Executes an expression that returns a StatusOr, extracting its value
38 // into the variable defined by lhs (or returning on error).
39 //
40 // Example: Assigning to an existing value
41 //   ValueType value;
42 //   ASSIGN_OR_RETURN(value, MaybeGetValue(arg));
43 //
44 // Example: Creating and assigning variable in one line.
45 //   ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(arg));
46 //   DoSomethingWithValueType(value);
47 //
48 // WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
49 //  in a single statement (e.g. as the body of an if statement without {})!
50 #define ASSIGN_OR_RETURN(lhs, rexpr) \
51   ASSIGN_OR_RETURN_IMPL(             \
52       STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr)
53 
54 #define ASSIGN_OR_ONCE_CALLBACK_AND_RETURN_IMPL(result, lhs, callback, rexpr) \
55   const auto result = (rexpr);                                                \
56   if (__builtin_expect(!result.ok(), 0)) {                                    \
57     std::move(callback).Run(result.status());                                 \
58     return;                                                                   \
59   }                                                                           \
60   lhs = result.ValueOrDie();
61 
62 // Executes an expression that returns a StatusOr, extracting its value into the
63 // variabled defined by lhs (or calls callback with error and returns).
64 //
65 // Example:
66 //   base::OnceCallback<void(Status)> callback =
67 //     base::BindOnce([](Status status) {...});
68 //   ASSIGN_OR_ONCE_CALLBACK_AND_RETURN(ValueType value,
69 //                                      callback,
70 //                                      MaybeGetValue(arg));
71 //
72 // WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
73 //  in a single statement (e.g. as the body of an if statement without {})!
74 #define ASSIGN_OR_ONCE_CALLBACK_AND_RETURN(lhs, callback, rexpr)               \
75   ASSIGN_OR_ONCE_CALLBACK_AND_RETURN_IMPL(                                     \
76       STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, callback, \
77       rexpr)
78 
79 }  // namespace reporting
80 
81 #endif  // CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_STATUS_MACROS_H_
82