Merge "android::base::Result supports cutsom error code"
diff --git a/include/android-base/result.h b/include/android-base/result.h
index acec791..faa722e 100644
--- a/include/android-base/result.h
+++ b/include/android-base/result.h
@@ -14,66 +14,68 @@
  * limitations under the License.
  */
 
-// This file contains classes for returning a successful result along with an optional
-// arbitrarily typed return value or for returning a failure result along with an optional string
-// indicating why the function failed.
-
-// There are 3 classes that implement this functionality and one additional helper type.
+// 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.
 //
-// Result<T> either contains a member of type T that can be accessed using similar semantics as
-// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
-// Result<T>::error().
+// Passing a success value or an error value:
 //
-// ResultError is a type that contains both a std::string describing the error and a copy of errno
-// from when the error occurred.  ResultError can be used in an ostream directly to print its
-// string value.
-//
-// Result<void> is the correct return type for a function that either returns successfully or
-// returns an error value.  Returning {} from a function that returns Result<void> is the
-// correct way to indicate that a function without a return type has completed successfully.
-//
-// A successful Result<T> is constructed implicitly from any type that can be implicitly converted
-// to T or from the constructor arguments for T.  This allows you to return a type T directly from
-// a function that returns Result<T>.
-//
-// Error and ErrnoError are used to construct a Result<T> that has failed.  The Error class takes
-// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
-// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
-// to the end of the failure string to aid in interacting with C APIs.  Alternatively, an errno
-// value can be directly specified via the Error() constructor.
-//
-// Errorf and ErrnoErrorf accept the format string syntax of the fmblib (https://fmt.dev).
-// Errorf("{} errors", num) is equivalent to Error() << num << " errors".
-//
-// ResultError can be used in the ostream and when using Error/Errorf to construct a Result<T>.
-// In this case, the string that the ResultError takes is passed through the stream normally, but
-// the errno is passed to the Result<T>. This can be used to pass errno from a failing C function up
-// multiple callers. Note that when the outer Result<T> is created with ErrnoError/ErrnoErrorf then
-// the errno from the inner ResultError is not passed. Also when multiple ResultError objects are
-// used, the errno of the last one is respected.
-//
-// ResultError can also directly construct a Result<T>.  This is particularly useful if you have a
-// function that return Result<T> but you have a Result<U> and want to return its error.  In this
-// case, you can return the .error() from the Result<U> to construct the Result<T>.
-
-// An example of how to use these is below:
-// Result<U> CalculateResult(const T& input) {
-//   U output;
-//   if (!SomeOtherCppFunction(input, &output)) {
-//     return Errorf("SomeOtherCppFunction {} failed", input);
+// Result<std::string> readFile() {
+//   std::string content;
+//   if (base::ReadFileToString("path", &content)) {
+//     return content; // ok case
+//   } else {
+//     return ErrnoError() << "failed to read"; // error case
 //   }
-//   if (!c_api_function(output)) {
-//     return ErrnoErrorf("c_api_function {} failed", output);
-//   }
-//   return output;
 // }
 //
-// auto output = CalculateResult(input);
-// if (!output) return Error() << "CalculateResult failed: " << output.error();
-// UseOutput(*output);
+// 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 };
+// struct MyErrorPrinter {
+//   static std::string print(const MyError& e) {
+//     switch(e) {
+//       MyError::A: return "A";
+//       MyError::B: return "B";
+//     }
+//   }
+// };
+//
+// #define NewMyError(e) Error<MyError, MyErrorPrinter>(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 <sstream>
@@ -85,54 +87,65 @@
 namespace android {
 namespace base {
 
+template <typename E = int>
 struct ResultError {
   template <typename T>
-  ResultError(T&& message, int code) : message_(std::forward<T>(message)), code_(code) {}
+  ResultError(T&& message, E code) : message_(std::forward<T>(message)), code_(code) {}
 
   template <typename T>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  operator android::base::expected<T, ResultError>() {
-    return android::base::unexpected(ResultError(message_, code_));
+  operator android::base::expected<T, ResultError<E>>() const {
+    return android::base::unexpected(ResultError<E>(message_, code_));
   }
 
   std::string message() const { return message_; }
-  int code() const { return code_; }
+  E code() const { return code_; }
 
  private:
   std::string message_;
-  int code_;
+  E code_;
 };
 
-inline bool operator==(const ResultError& lhs, const ResultError& rhs) {
+template <typename E>
+inline bool operator==(const ResultError<E>& lhs, const ResultError<E>& rhs) {
   return lhs.message() == rhs.message() && lhs.code() == rhs.code();
 }
 
-inline bool operator!=(const ResultError& lhs, const ResultError& rhs) {
+template <typename E>
+inline bool operator!=(const ResultError<E>& lhs, const ResultError<E>& rhs) {
   return !(lhs == rhs);
 }
 
-inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
+template <typename E>
+inline std::ostream& operator<<(std::ostream& os, const ResultError<E>& t) {
   os << t.message();
   return os;
 }
 
+struct ErrnoPrinter {
+  static std::string print(const int& e) { return strerror(e); }
+};
+
+template <typename E = int, typename ErrorCodePrinter = ErrnoPrinter>
 class Error {
  public:
-  Error() : errno_(0), append_errno_(false) {}
+  Error() : code_(0), has_code_(false) {}
   // NOLINTNEXTLINE(google-explicit-constructor)
-  Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
+  Error(E code) : code_(code), has_code_(true) {}
 
-  template <typename T>
+  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>() {
-    return android::base::unexpected(ResultError(str(), errno_));
+  operator android::base::expected<T, ResultError<P>>() const {
+    return android::base::unexpected(ResultError<P>(str(), static_cast<P>(code_)));
   }
 
   template <typename T>
   Error& operator<<(T&& t) {
     // NOLINTNEXTLINE(bugprone-suspicious-semicolon)
-    if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError>) {
-      errno_ = t.code();
+    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;
@@ -143,11 +156,11 @@
 
   const std::string str() const {
     std::string str = ss_.str();
-    if (append_errno_) {
+    if (has_code_) {
       if (str.empty()) {
-        return strerror(errno_);
+        return ErrorCodePrinter::print(code_);
       }
-      return std::move(str) + ": " + strerror(errno_);
+      return std::move(str) + ": " + ErrorCodePrinter::print(code_);
     }
     return str;
   }
@@ -164,49 +177,49 @@
   friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args);
 
  private:
-  Error(bool append_errno, int errno_to_append, const std::string& message)
-      : errno_(errno_to_append), append_errno_(append_errno) {
+  Error(bool has_code, E code, const std::string& message) : code_(code), has_code_(has_code) {
     (*this) << message;
   }
 
   std::stringstream ss_;
-  int errno_;
-  const bool append_errno_;
+  E code_;
+  const bool has_code_;
 };
 
-inline Error ErrnoError() {
-  return Error(errno);
+inline Error<int, ErrnoPrinter> ErrnoError() {
+  return Error<int, ErrnoPrinter>(errno);
 }
 
-inline int ErrorCode(int code) {
+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... Args>
-inline int ErrorCode(int code, T&& t, const Args&... args) {
-  if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError>) {
+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...);
 }
 
 template <typename T, typename... Args>
-inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
+inline Error<int, ErrnoPrinter> ErrorfImpl(const T&& fmt, const Args&... args) {
   return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
 }
 
 template <typename T, typename... Args>
-inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
-  return Error(true, errno, fmt::format(fmt, args...));
+inline Error<int, ErrnoPrinter> ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
+  return Error<int, ErrnoPrinter>(true, 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 <typename T>
-using Result = android::base::expected<T, ResultError>;
+template <typename T, typename E = int>
+using Result = android::base::expected<T, ResultError<E>>;
 
 // Macros for testing the results of functions that return android::base::Result.
 // These also work with base::android::expected.
@@ -230,7 +243,5 @@
     EXPECT_TRUE(tmp.ok()) << tmp.error(); \
   } while (0)
 
-// TODO: Maybe add RETURN_IF_ERROR() and ASSIGN_OR_RETURN()
-
 }  // namespace base
 }  // namespace android
diff --git a/result_test.cpp b/result_test.cpp
index 88eb658..592b0b8 100644
--- a/result_test.cpp
+++ b/result_test.cpp
@@ -191,6 +191,43 @@
   EXPECT_EQ(error_text + ": " + strerror(test_errno), result2.error().message());
 }
 
+enum class CustomError { A, B };
+struct CustomErrorPrinter {
+  static std::string print(const CustomError& e) {
+    switch (e) {
+      case CustomError::A:
+        return "A";
+      case CustomError::B:
+        return "B";
+    }
+  }
+};
+
+#define NewCustomError(e) Error<CustomError, CustomErrorPrinter>(CustomError::e)
+
+TEST(result, result_with_custom_errorcode) {
+  Result<void, CustomError> ok = {};
+  EXPECT_RESULT_OK(ok);
+  ok.value();  // should not crash
+  EXPECT_DEATH(ok.error(), "");
+
+  auto error_text = "test error"s;
+  Result<void, CustomError> err = NewCustomError(A) << error_text;
+
+  EXPECT_FALSE(err.ok());
+  EXPECT_FALSE(err.has_value());
+
+  EXPECT_EQ(CustomError::A, err.error().code());
+  EXPECT_EQ(error_text + ": A", err.error().message());
+}
+
+Result<std::string, CustomError> success_or_fail(bool success) {
+  if (success)
+    return "success";
+  else
+    return NewCustomError(A) << "fail";
+}
+
 TEST(result, constructor_forwarding) {
   auto result = Result<std::string>(std::in_place, 5, 'a');