OR_RETURN supports status_t

This change provide a specialization of android::base::OkOrFail for
status_t. As a result, a statement whose type is status_t can be used
with OR_RETURN.

The specialization also provides conversion operators to Result<T,
StatusT> where StatusT is a wrapper type for status_t. This allows
OR_RETURN macro to be used in newer functions that returns Result<T,
StatusT>.

Example usage:

\#include <utils/ErrorsMacros.h>

status_t legacy_inner();

status_t legacy_outer() {
  OR_RETURN(legacy_inner());
  return OK;
}

Result<T, StatusT> new_outer() {
  OR_RETURN(legacy_inner()); // the same macro
  return T{...};
}

Bug: 209929099
Test: atest libutils_test
Change-Id: I0def0e84ce3f0c4ff6d508c202bd51902dfc9618
diff --git a/libutils/Android.bp b/libutils/Android.bp
index e6d9a4c..45d010f 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -32,12 +32,14 @@
         "libsystem_headers",
         "libcutils_headers",
         "libprocessgroup_headers",
+        "libbase_headers",
     ],
     export_header_lib_headers: [
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
         "libprocessgroup_headers",
+        "libbase_headers",
     ],
     export_include_dirs: ["include"],
 
@@ -297,13 +299,14 @@
 
     srcs: [
         "BitSet_test.cpp",
+        "Errors_test.cpp",
         "FileMap_test.cpp",
         "LruCache_test.cpp",
         "Mutex_test.cpp",
         "SharedBuffer_test.cpp",
         "Singleton_test.cpp",
-        "String8_test.cpp",
         "String16_test.cpp",
+        "String8_test.cpp",
         "StrongPointer_test.cpp",
         "Timers_test.cpp",
         "Unicode_test.cpp",
@@ -362,6 +365,7 @@
         "-Wall",
         "-Werror",
     ],
+    header_libs: ["libutils_headers"],
 }
 
 cc_test_library {
@@ -374,6 +378,7 @@
         "-Werror",
     ],
     shared_libs: ["libutils_test_singleton1"],
+    header_libs: ["libutils_headers"],
 }
 
 cc_benchmark {
diff --git a/libutils/Errors_test.cpp b/libutils/Errors_test.cpp
new file mode 100644
index 0000000..873c994
--- /dev/null
+++ b/libutils/Errors_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "utils/ErrorsMacros.h"
+
+#include <android-base/result.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+using android::base::Error;
+using android::base::Result;
+
+status_t success_or_fail(bool success) {
+    if (success)
+        return OK;
+    else
+        return PERMISSION_DENIED;
+}
+
+TEST(errors, unwrap_or_return) {
+    auto f = [](bool success, int* val) -> status_t {
+        OR_RETURN(success_or_fail(success));
+        *val = 10;
+        return OK;
+    };
+
+    int val;
+    status_t s = f(true, &val);
+    EXPECT_EQ(OK, s);
+    EXPECT_EQ(10, val);
+
+    val = 0;  // reset
+    status_t q = f(false, &val);
+    EXPECT_EQ(PERMISSION_DENIED, q);
+    EXPECT_EQ(0, val);
+}
+
+TEST(errors, unwrap_or_return_result) {
+    auto f = [](bool success) -> Result<std::string, StatusT> {
+        OR_RETURN(success_or_fail(success));
+        return "hello";
+    };
+
+    auto r = f(true);
+    EXPECT_TRUE(r.ok());
+    EXPECT_EQ("hello", *r);
+
+    auto s = f(false);
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(PERMISSION_DENIED, s.error().code());
+    EXPECT_EQ("PERMISSION_DENIED", s.error().message());
+}
+
+TEST(errors, unwrap_or_return_result_int) {
+    auto f = [](bool success) -> Result<int, StatusT> {
+        OR_RETURN(success_or_fail(success));
+        return 10;
+    };
+
+    auto r = f(true);
+    EXPECT_TRUE(r.ok());
+    EXPECT_EQ(10, *r);
+
+    auto s = f(false);
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(PERMISSION_DENIED, s.error().code());
+    EXPECT_EQ("PERMISSION_DENIED", s.error().message());
+}
+
+TEST(errors, unwrap_or_fatal) {
+    OR_FATAL(success_or_fail(true));
+
+    EXPECT_DEATH(OR_FATAL(success_or_fail(false)), "PERMISSION_DENIED");
+}
+
+TEST(errors, result_in_status) {
+    auto f = [](bool success) -> Result<std::string, StatusT> {
+        if (success)
+            return "OK";
+        else
+            return Error<StatusT>(PERMISSION_DENIED) << "custom error message";
+    };
+
+    auto g = [&](bool success) -> status_t {
+        std::string val = OR_RETURN(f(success));
+        EXPECT_EQ("OK", val);
+        return OK;
+    };
+
+    status_t a = g(true);
+    EXPECT_EQ(OK, a);
+
+    status_t b = g(false);
+    EXPECT_EQ(PERMISSION_DENIED, b);
+}
diff --git a/libutils/include/utils/ErrorsMacros.h b/libutils/include/utils/ErrorsMacros.h
new file mode 100644
index 0000000..048c538
--- /dev/null
+++ b/libutils/include/utils/ErrorsMacros.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include "Errors.h"
+
+// It would have been better if this file (ErrorsMacros.h) is entirely in utils/Errors.h. However
+// that is infeasible as some (actually many) are using utils/Errors.h via the implicit include path
+// `system/core/include` [1].  Since such users are not guaranteed to specify the dependency to
+// libbase_headers, the following headers from libbase_headers can't be found.
+// [1] build/soong/cc/config/global.go#commonGlobalIncludes
+#include <android-base/errors.h>
+#include <android-base/result.h>
+
+#include <assert.h>
+
+namespace android {
+
+// StatusT is a wrapper class for status_t. Use this type instead of status_t when instantiating
+// Result<T, E> and Error<E> template classes. This is required to distinguish status_t from
+// other integer-based error code types like errno, and also to provide utility functions like
+// print().
+struct StatusT {
+    StatusT() : val_(OK) {}
+    StatusT(status_t s) : val_(s) {}
+    const status_t& value() const { return val_; }
+    operator status_t() const { return val_; }
+    std::string print() const { return statusToString(val_); }
+
+    status_t val_;
+};
+
+namespace base {
+
+// Specialization of android::base::OkOrFail<V> for V = status_t. This is used to use the OR_RETURN
+// and OR_FATAL macros with statements that yields a value of status_t. See android-base/errors.h
+// for the detailed contract.
+template <>
+struct OkOrFail<status_t> {
+    // Tests if status_t is a success value of not.
+    static bool IsOk(const status_t& s) { return s == OK; }
+
+    // Unwrapping status_t in the success case is just asserting that it is actually a success.
+    // We don't return OK because it would be redundant.
+    static void Unwrap([[maybe_unused]] status_t&& s) { assert(IsOk(s)); }
+
+    // Consumes status_t when it's a fail value
+    static OkOrFail<status_t> Fail(status_t&& s) {
+        assert(!IsOk(s));
+        return OkOrFail<status_t>{s};
+    }
+    status_t val_;
+
+    // And converts back into status_t. This is used when OR_RETURN is used in a function whose
+    // return type is status_t.
+    operator status_t() && { return val_; }
+
+    // Or converts into Result<T, StatusT>. This is used when OR_RETURN is used in a function whose
+    // return type is Result<T, StatusT>.
+    template <typename T, typename = std::enable_if_t<!std::is_same_v<T, status_t>>>
+    operator Result<T, StatusT>() && {
+        return Error<StatusT>(std::move(val_));
+    }
+
+    operator Result<int, StatusT>() && { return Error<StatusT>(std::move(val_)); }
+
+    // String representation of the error value.
+    static std::string ErrorMessage(const status_t& s) { return statusToString(s); }
+};
+
+}  // namespace base
+}  // namespace android