• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <utility>
17 
18 #include "pw_status/status.h"
19 #include "pw_status/status_with_size.h"
20 
21 // Macros for cleanly working with Status or StatusWithSize objects in functions
22 // that return Status.
23 
24 /// Returns early if \a expr is a non-OK `Status` or `Result`.
25 #define PW_TRY(expr) _PW_TRY(_PW_TRY_UNIQUE(__LINE__), expr)
26 
27 #define _PW_TRY(result, expr)                         \
28   do {                                                \
29     if (auto result = (expr); !result.ok()) {         \
30       return ::pw::internal::ConvertToStatus(result); \
31     }                                                 \
32   } while (0)
33 
34 /// Returns early if \a expression is a non-OK `Result`.
35 /// If \a expression is okay, assigns the inner value to \a lhs.
36 #define PW_TRY_ASSIGN(lhs, expression) \
37   _PW_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), lhs, expression)
38 
39 #define _PW_TRY_ASSIGN(result, lhs, expr)           \
40   auto result = (expr);                             \
41   if (!result.ok()) {                               \
42     return ::pw::internal::ConvertToStatus(result); \
43   }                                                 \
44   lhs = ::pw::internal::ConvertToValue(result)
45 
46 /// Returns early if \a expr is a non-OK `Status` or `StatusWithSize`.
47 ///
48 /// This is designed for use in functions that return a `StatusWithSize`.
49 #define PW_TRY_WITH_SIZE(expr) _PW_TRY_WITH_SIZE(_PW_TRY_UNIQUE(__LINE__), expr)
50 
51 #define _PW_TRY_WITH_SIZE(result, expr)                       \
52   do {                                                        \
53     if (auto result = (expr); !result.ok()) {                 \
54       return ::pw::internal::ConvertToStatusWithSize(result); \
55     }                                                         \
56   } while (0)
57 
58 #define _PW_TRY_UNIQUE(line) _PW_TRY_UNIQUE_EXPANDED(line)
59 #define _PW_TRY_UNIQUE_EXPANDED(line) _pw_try_unique_name_##line
60 
61 /// Like `PW_TRY`, but using `co_return` instead of early `return`.
62 ///
63 /// This is necessary because only `co_return` can be used inside of a
64 /// coroutine, and there is no way to detect whether particular code is running
65 /// within a coroutine or not.
66 #define PW_CO_TRY(expr) _PW_CO_TRY(_PW_TRY_UNIQUE(__LINE__), expr)
67 
68 #define _PW_CO_TRY(result, expr)                         \
69   do {                                                   \
70     if (auto result = (expr); !result.ok()) {            \
71       co_return ::pw::internal::ConvertToStatus(result); \
72     }                                                    \
73   } while (0)
74 
75 /// Like `PW_TRY_ASSIGN`, but using `co_return` instead of early `return`.
76 ///
77 /// This is necessary because only `co_return` can be used inside of a
78 /// coroutine, and there is no way to detect whether particular code is running
79 /// within a coroutine or not.
80 #define PW_CO_TRY_ASSIGN(lhs, expression) \
81   _PW_CO_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), lhs, expression)
82 
83 #define _PW_CO_TRY_ASSIGN(result, lhs, expr)           \
84   auto result = (expr);                                \
85   if (!result.ok()) {                                  \
86     co_return ::pw::internal::ConvertToStatus(result); \
87   }                                                    \
88   lhs = ::pw::internal::ConvertToValue(result);
89 
90 namespace pw::internal {
91 
ConvertToStatus(Status status)92 constexpr Status ConvertToStatus(Status status) { return status; }
93 
ConvertToStatus(StatusWithSize status_with_size)94 constexpr Status ConvertToStatus(StatusWithSize status_with_size) {
95   return status_with_size.status();
96 }
97 
ConvertToValue(StatusWithSize status_with_size)98 constexpr size_t ConvertToValue(StatusWithSize status_with_size) {
99   return status_with_size.size();
100 }
101 
ConvertToStatusWithSize(Status status)102 constexpr StatusWithSize ConvertToStatusWithSize(Status status) {
103   return StatusWithSize(status, 0);
104 }
105 
ConvertToStatusWithSize(StatusWithSize status_with_size)106 constexpr StatusWithSize ConvertToStatusWithSize(
107     StatusWithSize status_with_size) {
108   return status_with_size;
109 }
110 
111 }  // namespace pw::internal
112