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