/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Result is the type that is used to pass a success value of type T or an error code of type // E, optionally together with an error message. T and E can be any type. If E is omitted it // defaults to int, which is useful when errno(3) is used as the error code. // // Passing a success value or an error value: // // Result readFile() { // std::string content; // if (base::ReadFileToString("path", &content)) { // return content; // ok case // } else { // return ErrnoError() << "failed to read"; // error case // } // } // // Checking the result and then unwrapping the value or propagating the error: // // Result hasAWord() { // auto content = readFile(); // if (!content.ok()) { // return Error() << "failed to process: " << content.error(); // } // return (*content.find("happy") != std::string::npos); // } // // Using custom error code type: // // enum class MyError { A, B }; // assume that this is the error code you already have // // // To use the error code with Result, define a wrapper class that provides the following // operations and use the wrapper class as the second type parameter (E) when instantiating // Result // // 1. default constructor // 2. copy constructor / and move constructor if copying is expensive // 3. conversion operator to the error code type // 4. value() function that return the error code value // 5. print() function that gives a string representation of the error ode value // // struct MyErrorWrapper { // MyError val_; // MyErrorWrapper() : val_(/* reasonable default value */) {} // MyErrorWrapper(MyError&& e) : val_(std:forward(e)) {} // operator const MyError&() const { return val_; } // MyError value() const { return val_; } // std::string print() const { // switch(val_) { // MyError::A: return "A"; // MyError::B: return "B"; // } // } // }; // // #define NewMyError(e) Error(MyError::e) // // Result val = NewMyError(A) << "some message"; // // Formatting the error message using fmtlib: // // Errorf("{} errors", num); // equivalent to Error() << num << " errors"; // ErrnoErrorf("{} errors", num); // equivalent to ErrnoError() << num << " errors"; // // Returning success or failure, but not the value: // // Result doSomething() { // if (success) return {}; // else return Error() << "error occurred"; // } // // Extracting error code: // // Result val = Error(3) << "some error occurred"; // assert(3 == val.error().code()); // #pragma once #include #include #include #include #include #include "android-base/errors.h" #include "android-base/expected.h" #include "android-base/format.h" namespace android { namespace base { // Errno is a wrapper class for errno(3). Use this type instead of `int` when instantiating // `Result` and `Error` template classes. This is required to distinguish errno from other // integer-based error code types like `status_t`. struct Errno { Errno() : val_(0) {} Errno(int e) : val_(e) {} int value() const { return val_; } operator int() const { return value(); } std::string print() const { return strerror(value()); } int val_; // TODO(b/209929099): remove this conversion operator. This currently is needed to not break // existing places where error().code() is used to construct enum values. template >> operator E() const { return E(val_); } }; template struct ResultError { template >> ResultError(T&& message, P&& code) : message_(std::forward(message)), code_(E(std::forward

(code))) {} template // NOLINTNEXTLINE(google-explicit-constructor) operator android::base::expected>() const { return android::base::unexpected(ResultError(message_, code_)); } std::string message() const { return message_; } const E& code() const { return code_; } private: std::string message_; E code_; }; template struct ResultError { template >> ResultError(P&& code) : code_(E(std::forward

(code))) {} template operator android::base::expected>() const { return android::base::unexpected(ResultError(code_)); } const E& code() const { return code_; } private: E code_; }; template inline bool operator==(const ResultError& lhs, const ResultError& rhs) { return lhs.message() == rhs.message() && lhs.code() == rhs.code(); } template inline bool operator!=(const ResultError& lhs, const ResultError& rhs) { return !(lhs == rhs); } template inline std::ostream& operator<<(std::ostream& os, const ResultError& t) { os << t.message(); return os; } namespace internal { // Stream class that does nothing and is has zero (actually 1) size. It is used instead of // std::stringstream when include_message is false so that we use less on stack. // sizeof(std::stringstream) is 280 on arm64. struct DoNothingStream { template DoNothingStream& operator<<(T&&) { return *this; } std::string str() const { return ""; } }; } // namespace internal template >> class Error { public: Error() : code_(0), has_code_(false) {} template >> // NOLINTNEXTLINE(google-explicit-constructor) Error(P&& code) : code_(std::forward

(code)), has_code_(true) {} template >> // NOLINTNEXTLINE(google-explicit-constructor) operator android::base::expected>() const { return android::base::unexpected(ResultError

(str(), static_cast

(code_))); } template >> // NOLINTNEXTLINE(google-explicit-constructor) operator android::base::expected>() const { return android::base::unexpected(ResultError(static_cast

(code_))); } template Error& operator<<(T&& t) { static_assert(include_message, "<< not supported when include_message = false"); // NOLINTNEXTLINE(bugprone-suspicious-semicolon) if constexpr (std::is_same_v>, ResultError>) { if (!has_code_) { code_ = t.code(); } return (*this) << t.message(); } int saved = errno; ss_ << t; errno = saved; return *this; } const std::string str() const { static_assert(include_message, "str() not supported when include_message = false"); std::string str = ss_.str(); if (has_code_) { if (str.empty()) { return code_.print(); } return std::move(str) + ": " + code_.print(); } return str; } Error(const Error&) = delete; Error(Error&&) = delete; Error& operator=(const Error&) = delete; Error& operator=(Error&&) = delete; template friend Error ErrorfImpl(const T&& fmt, const Args&... args); template friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args); private: Error(bool has_code, E code, const std::string& message) : code_(code), has_code_(has_code) { (*this) << message; } std::conditional_t ss_; E code_; const bool has_code_; }; inline Error ErrnoError() { return Error(Errno{errno}); } template inline E ErrorCode(E code) { return code; } // Return the error code of the last ResultError object, if any. // Otherwise, return `code` as it is. template inline E ErrorCode(E code, T&& t, const Args&... args) { if constexpr (std::is_same_v>, ResultError>) { return ErrorCode(t.code(), args...); } return ErrorCode(code, args...); } template inline Error ErrorfImpl(const T&& fmt, const Args&... args) { return Error(false, ErrorCode(Errno{}, args...), fmt::format(fmt, args...)); } template inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) { return Error(true, Errno{errno}, fmt::format(fmt, args...)); } #define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) #define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) template using Result = android::base::expected>; // Specialization of android::base::OkOrFail for V = Result. See android-base/errors.h // for the contract. namespace impl { template using Code = std::decay_t().error().code())>; template using ErrorType = std::decay_t().error())>; template constexpr bool IsNumeric = std::is_integral_v || std::is_floating_point_v || (std::is_enum_v && std::is_convertible_v); // This base class exists to take advantage of shadowing // We include the conversion in this base class so that if the conversion in NumericConversions // overlaps, we (arbitrarily) choose the implementation in NumericConversions due to shadowing. template struct ConversionBase { ErrorType error_; // T is a expected>. operator const T() const && { return unexpected(std::move(error_)); } operator const Code() const && { return error_.code(); } }; // User defined conversions can be followed by numeric conversions // Although we template specialize for the exact code type, we need // specializations for conversions to all numeric types to avoid an // ambiguous conversion sequence. template struct NumericConversions : public ConversionBase {}; template struct NumericConversions>> > : public ConversionBase { #pragma push_macro("SPECIALIZED_CONVERSION") #define SPECIALIZED_CONVERSION(type)\ operator const expected>() const &&\ { return unexpected(std::move(this->error_));} SPECIALIZED_CONVERSION(int) SPECIALIZED_CONVERSION(short int) SPECIALIZED_CONVERSION(unsigned short int) SPECIALIZED_CONVERSION(unsigned int) SPECIALIZED_CONVERSION(long int) SPECIALIZED_CONVERSION(unsigned long int) SPECIALIZED_CONVERSION(long long int) SPECIALIZED_CONVERSION(unsigned long long int) SPECIALIZED_CONVERSION(bool) SPECIALIZED_CONVERSION(char) SPECIALIZED_CONVERSION(unsigned char) SPECIALIZED_CONVERSION(signed char) SPECIALIZED_CONVERSION(wchar_t) SPECIALIZED_CONVERSION(char16_t) SPECIALIZED_CONVERSION(char32_t) SPECIALIZED_CONVERSION(float) SPECIALIZED_CONVERSION(double) SPECIALIZED_CONVERSION(long double) #undef SPECIALIZED_CONVERSION #pragma pop_macro("SPECIALIZED_CONVERSION") // For debugging purposes using IsNumericT = std::true_type; }; #ifdef __cpp_concepts template concept Trivial = std::is_same_v; #endif } // namespace impl template struct OkOrFail> : public impl::NumericConversions> { using V = Result; using Err = impl::ErrorType; using C = impl::Code; private: OkOrFail(Err&& v): impl::NumericConversions{std::move(v)} {} OkOrFail(const OkOrFail& other) = delete; OkOrFail(const OkOrFail&& other) = delete; public: // Checks if V is ok or fail static bool IsOk(const V& val) { return val.ok(); } // Turns V into a success value static T Unwrap(V&& val) { return std::move(val.value()); } // Consumes V when it's a fail value static const OkOrFail Fail(V&& v) { assert(!IsOk(v)); return OkOrFail{std::move(v.error())}; } // We specialize as much as possible to avoid ambiguous conversion with // templated expected ctor operator const Result() const && { return unexpected(std::move(this->error_)); } #ifdef __cpp_concepts template #else template #endif operator const Result() const && { return unexpected(std::move(this->error_)); } static std::string ErrorMessage(const V& val) { return val.error().message(); } }; // Macros for testing the results of functions that return android::base::Result. // These also work with base::android::expected. // For advanced matchers and customized error messages, see result-gtest.h. #define ASSERT_RESULT_OK(stmt) \ if (const auto& tmp = (stmt); !tmp.ok()) \ FAIL() << "Value of: " << #stmt << "\n" \ << " Actual: " << tmp.error().message() << "\n" \ << "Expected: is ok\n" #define EXPECT_RESULT_OK(stmt) \ if (const auto& tmp = (stmt); !tmp.ok()) \ ADD_FAILURE() << "Value of: " << #stmt << "\n" \ << " Actual: " << tmp.error().message() << "\n" \ << "Expected: is ok\n" } // namespace base } // namespace android