| /* |
| * 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<T, E> 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<std::string> 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<bool> 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<T, E> |
| // |
| // 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<MyError>(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<MyErrorWrapper>(MyError::e) |
| // |
| // Result<T, MyError> 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<void> doSomething() { |
| // if (success) return {}; |
| // else return Error() << "error occurred"; |
| // } |
| // |
| // Extracting error code: |
| // |
| // Result<T> val = Error(3) << "some error occurred"; |
| // assert(3 == val.error().code()); |
| // |
| |
| #pragma once |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <string.h> |
| |
| #include <sstream> |
| #include <string> |
| #include <type_traits> |
| |
| #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<T, E>` and `Error<E>` 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(); } |
| const char* 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 <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> |
| operator E() const { |
| return E(val_); |
| } |
| }; |
| |
| static_assert(std::is_trivially_copyable_v<Errno> == true); |
| |
| template <typename E = Errno, bool include_message = true> |
| struct ResultError { |
| template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>> |
| ResultError(T&& message, P&& code) |
| : message_(std::forward<T>(message)), code_(E(std::forward<P>(code))) {} |
| |
| ResultError(const ResultError& other) = default; |
| ResultError(ResultError&& other) = default; |
| ResultError& operator=(const ResultError& other) = default; |
| ResultError& operator=(ResultError&& other) = default; |
| |
| template <typename T> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator android::base::expected<T, ResultError<E>>() && { |
| return android::base::unexpected(std::move(*this)); |
| } |
| |
| template <typename T> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator android::base::expected<T, ResultError<E>>() const& { |
| return android::base::unexpected(*this); |
| } |
| |
| const std::string& message() const { return message_; } |
| const E& code() const { return code_; } |
| |
| private: |
| std::string message_; |
| E code_; |
| }; |
| |
| template <typename E> |
| auto format_as(ResultError<E, true> error) { |
| return error.message(); |
| } |
| |
| template <typename E> |
| struct ResultError<E, /* include_message */ false> { |
| template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>> |
| ResultError(P&& code) : code_(E(std::forward<P>(code))) {} |
| |
| template <typename T> |
| operator android::base::expected<T, ResultError<E, false>>() const { |
| return android::base::unexpected(ResultError<E, false>(code_)); |
| } |
| |
| const E& code() const { return code_; } |
| |
| private: |
| E code_; |
| }; |
| |
| template <typename E> |
| inline bool operator==(const ResultError<E>& lhs, const ResultError<E>& rhs) { |
| return lhs.message() == rhs.message() && lhs.code() == rhs.code(); |
| } |
| |
| template <typename E> |
| inline bool operator!=(const ResultError<E>& lhs, const ResultError<E>& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| template <typename E> |
| inline std::ostream& operator<<(std::ostream& os, const ResultError<E>& 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 <typename T> |
| DoNothingStream& operator<<(T&&) { |
| return *this; |
| } |
| |
| std::string str() const { return ""; } |
| }; |
| } // namespace internal |
| |
| template <typename E = Errno, bool include_message = true, |
| typename = std::enable_if_t<!std::is_same_v<E, int>>> |
| class Error { |
| public: |
| Error() : code_(0), has_code_(false) {} |
| template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| Error(P&& code) : code_(std::forward<P>(code)), has_code_(true) {} |
| |
| template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator android::base::expected<T, ResultError<P>>() const { |
| return android::base::unexpected(ResultError<P>(str(), static_cast<P>(code_))); |
| } |
| |
| template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator android::base::expected<T, ResultError<P, false>>() const { |
| return android::base::unexpected(ResultError<P, false>(static_cast<P>(code_))); |
| } |
| |
| template <typename T> |
| Error& operator<<(T&& t) { |
| static_assert(include_message, "<< not supported when include_message = false"); |
| // NOLINTNEXTLINE(bugprone-suspicious-semicolon) |
| if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError<E>>) { |
| 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 <typename... Args> |
| friend Error ErrorfImpl(fmt::format_string<Args...> fmt, const Args&... args); |
| |
| template <typename... Args> |
| friend Error ErrnoErrorfImpl(fmt::format_string<Args...> 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<include_message, std::stringstream, internal::DoNothingStream> ss_; |
| E code_; |
| const bool has_code_; |
| }; |
| |
| inline Error<Errno> ErrnoError() { |
| return Error<Errno>(Errno{errno}); |
| } |
| |
| template <typename E> |
| 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 <typename T, typename E, typename... Args> |
| inline E ErrorCode(E code, T&& t, const Args&... args) { |
| if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError<E>>) { |
| return ErrorCode(t.code(), args...); |
| } |
| return ErrorCode(code, args...); |
| } |
| |
| __attribute__((noinline)) ResultError<Errno> MakeResultErrorWithCode(std::string&& message, |
| Errno code); |
| |
| template <typename... Args> |
| inline ResultError<Errno> ErrorfImpl(fmt::format_string<Args...> fmt, const Args&... args) { |
| return ResultError(fmt::vformat(fmt.get(), fmt::make_format_args(args...)), |
| ErrorCode(Errno{}, args...)); |
| } |
| |
| template <typename... Args> |
| inline ResultError<Errno> ErrnoErrorfImpl(fmt::format_string<Args...> fmt, const Args&... args) { |
| Errno code{errno}; |
| return MakeResultErrorWithCode(fmt::vformat(fmt.get(), fmt::make_format_args(args...)), code); |
| } |
| |
| #define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) |
| #define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) |
| |
| template <typename T, typename E = Errno, bool include_message = true> |
| using Result = android::base::expected<T, ResultError<E, include_message>>; |
| |
| // Specialization of android::base::OkOrFail<V> for V = Result<T, E>. See android-base/errors.h |
| // for the contract. |
| |
| namespace impl { |
| template <typename U> |
| using Code = std::decay_t<decltype(std::declval<U>().error().code())>; |
| |
| template <typename U> |
| using ErrorType = std::decay_t<decltype(std::declval<U>().error())>; |
| |
| template <typename U> |
| constexpr bool IsNumeric = std::is_integral_v<U> || std::is_floating_point_v<U> || |
| (std::is_enum_v<U> && std::is_convertible_v<U, size_t>); |
| |
| // 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 <typename T> |
| struct ConversionBase { |
| ErrorType<T> error_; |
| // T is a expected<U, ErrorType<T>>. |
| operator T() const& { return unexpected(error_); } |
| operator T() && { return unexpected(std::move(error_)); } |
| |
| operator Code<T>() 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 <typename T, typename = void> |
| struct NumericConversions : public ConversionBase<T> {}; |
| template <typename T> |
| struct NumericConversions<T, |
| std::enable_if_t<impl::IsNumeric<impl::Code<T>>> |
| > : public ConversionBase<T> |
| { |
| #pragma push_macro("SPECIALIZED_CONVERSION") |
| #define SPECIALIZED_CONVERSION(type) \ |
| operator expected<type, ErrorType<T>>() const& { return unexpected(this->error_); } \ |
| operator expected<type, ErrorType<T>>()&& { 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 <class U> |
| // Define a concept which **any** type matches to |
| concept Universal = std::is_same_v<U, U>; |
| #endif |
| |
| // A type that is never used. |
| struct Never {}; |
| } // namespace impl |
| |
| template <typename T, typename E, bool include_message> |
| struct OkOrFail<Result<T, E, include_message>> |
| : public impl::NumericConversions<Result<T, E, include_message>> { |
| using V = Result<T, E, include_message>; |
| using Err = impl::ErrorType<V>; |
| using C = impl::Code<V>; |
| private: |
| OkOrFail(Err&& v): impl::NumericConversions<V>{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) { |
| if constexpr (std::is_same_v<T, void>) { |
| assert(IsOk(val)); |
| return; |
| } else { |
| return std::move(val.value()); |
| } |
| } |
| |
| // Consumes V when it's a fail value |
| static OkOrFail<V> Fail(V&& v) { |
| assert(!IsOk(v)); |
| return OkOrFail<V>{std::move(v.error())}; |
| } |
| |
| // We specialize as much as possible to avoid ambiguous conversion with templated expected ctor. |
| // We don't need this specialization if `C` is numeric because that case is already covered by |
| // `NumericConversions`. |
| operator Result<std::conditional_t<impl::IsNumeric<C>, impl::Never, C>, E, include_message>() |
| const& { |
| return unexpected(this->error_); |
| } |
| operator Result<std::conditional_t<impl::IsNumeric<C>, impl::Never, C>, E, include_message>() && { |
| return unexpected(std::move(this->error_)); |
| } |
| |
| #ifdef __cpp_concepts |
| // The idea here is to match this template method to any type (not simply trivial types). |
| // The reason for including a constraint is to take advantage of the fact that a constrained |
| // method always has strictly lower precedence than a non-constrained method in template |
| // specialization rules (thus avoiding ambiguity). So we use a universally matching constraint to |
| // mark this function as less preferable (but still accepting of all types). |
| template <impl::Universal U> |
| operator Result<U, E, include_message>() const& { |
| return unexpected(this->error_); |
| } |
| template <impl::Universal U> |
| operator Result<U, E, include_message>() && { |
| return unexpected(std::move(this->error_)); |
| } |
| #else |
| template <typename U> |
| operator Result<U, E, include_message>() const& { |
| return unexpected(this->error_); |
| } |
| template <typename U> |
| operator Result<U, E, include_message>() && { |
| return unexpected(std::move(this->error_)); |
| } |
| #endif |
| |
| static const 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 |