Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e060580c authored by Jiyong Park's avatar Jiyong Park Committed by Gerrit Code Review
Browse files

Merge changes from topic "or_return"

* changes:
  Sort exported headers of libutils
  OR_RETURN supports status_t
parents da0756b5 8b196a73
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ class ErrorIgnoreEnoent {
                        android::base::GetMinimumLogSeverity() > android::base::DEBUG) {}

    template <typename T>
    operator android::base::expected<T, ResultError<int>>() {
    operator android::base::expected<T, ResultError<android::base::Errno>>() {
        if (ignore_error_) {
            return {};
        }
+10 −5
Original line number Diff line number Diff line
@@ -28,16 +28,18 @@ cc_library_headers {
    min_sdk_version: "apex_inherit",

    header_libs: [
        "liblog_headers",
        "libsystem_headers",
        "libbase_headers",
        "libcutils_headers",
        "liblog_headers",
        "libprocessgroup_headers",
        "libsystem_headers",
    ],
    export_header_lib_headers: [
        "liblog_headers",
        "libsystem_headers",
        "libbase_headers",
        "libcutils_headers",
        "liblog_headers",
        "libprocessgroup_headers",
        "libsystem_headers",
    ],
    export_include_dirs: ["include"],

@@ -299,13 +301,14 @@ cc_test {

    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",
@@ -364,6 +367,7 @@ cc_test_library {
        "-Wall",
        "-Werror",
    ],
    header_libs: ["libutils_headers"],
}

cc_test_library {
@@ -376,6 +380,7 @@ cc_test_library {
        "-Werror",
    ],
    shared_libs: ["libutils_test_singleton1"],
    header_libs: ["libutils_headers"],
}

cc_benchmark {
+110 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+86 −0
Original line number Diff line number Diff line
/*
 * 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