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