• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "Errors.h"
20 
21 // It would have been better if this file (ErrorsMacros.h) is entirely in utils/Errors.h. However
22 // that is infeasible as some (actually many) are using utils/Errors.h via the implicit include path
23 // `system/core/include` [1].  Since such users are not guaranteed to specify the dependency to
24 // libbase_headers, the following headers from libbase_headers can't be found.
25 // [1] build/soong/cc/config/global.go#commonGlobalIncludes
26 #include <android-base/errors.h>
27 #include <android-base/result.h>
28 #include <log/log_main.h>
29 
30 #include <assert.h>
31 
32 namespace android {
33 
34 // StatusT is a wrapper class for status_t. Use this type instead of status_t when instantiating
35 // Result<T, E> and Error<E> template classes. This is required to distinguish status_t from
36 // other integer-based error code types like errno, and also to provide utility functions like
37 // print().
38 struct StatusT {
StatusTStatusT39     StatusT() : val_(OK) {}
StatusTStatusT40     StatusT(status_t s) : val_(s) {}
valueStatusT41     const status_t& value() const { return val_; }
status_tStatusT42     operator status_t() const { return val_; }
printStatusT43     std::string print() const { return statusToString(val_); }
44 
45     status_t val_;
46 };
47 
48 
49 namespace base {
50 // TODO(b/221235365) StatusT fulfill ResultError contract and cleanup.
51 
52 // Unlike typical ResultError types, the underlying code should be a status_t
53 // instead of a StatusT. We also special-case message generation.
54 template<>
55 struct ResultError<StatusT, false> {
56     ResultError(status_t s) : val_(s) {
57         LOG_FATAL_IF(s == OK, "Result error should not hold success");
58     }
59 
60     template <typename T>
61     operator expected<T, ResultError<StatusT, false>>() const {
62         return unexpected(*this);
63     }
64 
65     std::string message() const { return statusToString(val_); }
66     status_t code() const { return val_; }
67 
68  private:
69     const status_t val_;
70 };
71 
72 template<>
73 struct ResultError<StatusT, true> {
74     template <typename T>
75     ResultError(T&& message, status_t s) : val_(s), message_(std::forward<T>(message)) {
76         LOG_FATAL_IF(s == OK, "Result error should not hold success");
77     }
78 
79     ResultError(status_t s) : val_(s) {}
80 
81     template <typename T>
82     operator expected<T, ResultError<StatusT, true>>() const {
83         return unexpected(*this);
84     }
85 
86     status_t code() const { return val_; }
87 
88     std::string message() const { return statusToString(val_) + message_; }
89  private:
90     const status_t val_;
91     std::string message_;
92 };
93 
94 // Specialization of android::base::OkOrFail<V> for V = status_t. This is used to use the OR_RETURN
95 // and OR_FATAL macros with statements that yields a value of status_t. See android-base/errors.h
96 // for the detailed contract.
97 template <>
98 struct OkOrFail<status_t> {
99     static_assert(std::is_same_v<status_t, int>);
100     // Tests if status_t is a success value of not.
101     static bool IsOk(const status_t& s) { return s == OK; }
102 
103     // Unwrapping status_t in the success case is just asserting that it is actually a success.
104     // We don't return OK because it would be redundant.
105     static void Unwrap([[maybe_unused]] status_t&& s) { assert(IsOk(s)); }
106 
107     // Consumes status_t when it's a fail value
108     static OkOrFail<status_t> Fail(status_t&& s) {
109         assert(!IsOk(s));
110         return OkOrFail<status_t>{s};
111     }
112     status_t val_;
113 
114     // And converts back into status_t. This is used when OR_RETURN is used in a function whose
115     // return type is status_t.
116     operator status_t() && { return val_; }
117 
118     // Or converts into Result<T, StatusT>. This is used when OR_RETURN is used in a function whose
119     // return type is Result<T, StatusT>.
120 
121     template <typename T>
122     operator Result<T, StatusT>() && {
123         return ResultError<StatusT>(std::move(val_));
124     }
125 
126     template<typename T>
127     operator Result<T, StatusT, false>() && {
128         return ResultError<StatusT, false>(std::move(val_));
129     }
130 
131     // Since user defined conversion can be followed by numeric conversion,
132     // we have to specialize all conversions to results holding numeric types to
133     // avoid conversion ambiguities with the constructor of expected.
134 #pragma push_macro("SPECIALIZED_CONVERSION")
135 #define SPECIALIZED_CONVERSION(type)\
136   operator Result<type, StatusT>() && { return ResultError<StatusT>(std::move(val_)); }\
137   operator Result<type, StatusT, false>() && { return ResultError<StatusT, false>(std::move(val_));}
138 
139     SPECIALIZED_CONVERSION(int)
140     SPECIALIZED_CONVERSION(short int)
141     SPECIALIZED_CONVERSION(unsigned short int)
142     SPECIALIZED_CONVERSION(unsigned int)
143     SPECIALIZED_CONVERSION(long int)
144     SPECIALIZED_CONVERSION(unsigned long int)
145     SPECIALIZED_CONVERSION(long long int)
146     SPECIALIZED_CONVERSION(unsigned long long int)
147     SPECIALIZED_CONVERSION(bool)
148     SPECIALIZED_CONVERSION(char)
149     SPECIALIZED_CONVERSION(unsigned char)
150     SPECIALIZED_CONVERSION(signed char)
151     SPECIALIZED_CONVERSION(wchar_t)
152     SPECIALIZED_CONVERSION(char16_t)
153     SPECIALIZED_CONVERSION(char32_t)
154     SPECIALIZED_CONVERSION(float)
155     SPECIALIZED_CONVERSION(double)
156     SPECIALIZED_CONVERSION(long double)
157 #undef SPECIALIZED_CONVERSION
158 #pragma pop_macro("SPECIALIZED_CONVERSION")
159     // String representation of the error value.
160     static std::string ErrorMessage(const status_t& s) { return statusToString(s); }
161 };
162 }  // namespace base
163 
164 
165 // These conversions make StatusT directly comparable to status_t in order to
166 // avoid calling code whenever comparisons are desired.
167 
168 template <bool include_message>
169 bool operator==(const base::ResultError<StatusT, include_message>& l, const status_t& r) {
170     return (l.code() == r);
171 }
172 template <bool include_message>
173 bool operator==(const status_t& l, const base::ResultError<StatusT, include_message>& r) {
174     return (l == r.code());
175 }
176 
177 template <bool include_message>
178 bool operator!=(const base::ResultError<StatusT, include_message>& l, const status_t& r) {
179     return (l.code() != r);
180 }
181 template <bool include_message>
182 bool operator!=(const status_t& l, const base::ResultError<StatusT, include_message>& r) {
183     return (l != r.code());
184 }
185 
186 }  // namespace android
187