diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a56e03a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,18 @@ +name: Build + +on: [push] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + - name: Build + uses: ashutoshvarma/action-cmake-build@master + with: + build-dir: ${{ runner.workspace }}/build + build-type: Release + run-test: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 53a19ab..cd7734f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.12) +CMAKE_MINIMUM_REQUIRED(VERSION 3.6) PROJECT( PeeloResult - VERSION 0.1.0 + VERSION 0.2.0 DESCRIPTION "Header only C++ result type." HOMEPAGE_URL "https://github.com/peelonet/peelo-result" LANGUAGES CXX @@ -22,7 +22,7 @@ TARGET_INCLUDE_DIRECTORIES( TARGET_COMPILE_FEATURES( ${PROJECT_NAME} INTERFACE - cxx_std_17 + cxx_std_11 ) INSTALL( diff --git a/README.md b/README.md index 67f774e..a638ba7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # peelo-result -[![travis][travis-image]][travis-url] +![Build](https://github.com/peelonet/peelo-result/workflows/Build/badge.svg) Header only C++11 implementation of [Rust's Result type]. @@ -17,9 +17,10 @@ Header only C++11 implementation of [Rust's Result type]. and `error`. First one creates an "OK" result, which holds some kind of value, while the second one creates erroneous result which holds some kind of error. -Type of the error can be checked with the `type` method of `result` class. If -the result is of type `result::type::ok`, then it's value can be accessed with -the `value` method, otherwise it's error can be accessed with `error` method. +Whether an result contains an value or not can be checked with `has_value` +method of `result` class. If this method returns `true`, then it's value can be +accessed with the `value` method, otherwise it's error can be accessed with +the `error` method. **Note**: The underlying containers are implemented with [std::unique_ptr], so accessing `value` of erroneous result leads to undefined behavior and vice @@ -47,12 +48,12 @@ int main() if (ok_result) { - std::cout << "OK result: " << *ok_result.value() << std::endl; + std::cout << "OK result: " << ok_result.value() << std::endl; } if (!err_result) { - std::cout << "Error code: " << err_result->code << std::endl; + std::cout << "Error code: " << err_result.error().code << std::endl; } return 0; diff --git a/include/peelo/result.hpp b/include/peelo/result.hpp index 9cba458..60dcacb 100644 --- a/include/peelo/result.hpp +++ b/include/peelo/result.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, peelo.net + * Copyright (c) 2020-2024, peelo.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,8 +24,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PEELO_RESULT_HPP_GUARD -#define PEELO_RESULT_HPP_GUARD +#pragma once #include @@ -38,38 +37,29 @@ namespace peelo using value_type = T; using error_type = E; - enum class type + static inline result ok(const value_type& value) { - ok = 1, - error = 0 - }; - - static inline result ok(const T& value) - { - return result(type::ok, new value_type(value), nullptr); + return result(new value_type(value), nullptr); } - static inline result error(const E& error) + static inline result error(const error_type& error) { - return result(type::error, nullptr, new error_type(error)); + return result(nullptr, new error_type(error)); } result(const result& that) - : m_type(that.m_type) - , m_value(that.m_value ? new value_type(*that.m_value) : nullptr) + : m_value(that.m_value ? new value_type(*that.m_value) : nullptr) , m_error(that.m_error ? new error_type(*that.m_error) : nullptr) {} - template - result(const result& that) - : m_type(!!that ? type::ok : type::error) - , m_value(that.value() ? new value_type(*that.value()) : nullptr) - , m_error(that.error() ? new error_type(*that.error()) : nullptr) {} + template + result(const result& that) + : m_value(that ? new value_type(that.value()) : nullptr) + , m_error(that ? nullptr : new error_type(that.error())) {} result& operator=(const result& that) { if (this != &that) { - m_type = that.m_type; m_value.reset(that.m_value ? new value_type(*that.m_value) : nullptr); m_error.reset(that.m_error ? new error_type(*that.m_error) : nullptr); } @@ -77,46 +67,59 @@ namespace peelo return *this; } - template - result& operator=(const result& that) + template + result& operator=(const result& that) { - m_type = !!that ? type::ok : type::error; - m_value.reset(that.value() ? new value_type(*that.value()) : nullptr); - m_error.reset(that.error() ? new error_type(*that.error()) : nullptr); + const auto has_value = that.has_value(); + + m_value.reset(has_value ? new value_type(that.value()) : nullptr); + m_error.reset(has_value ? nullptr : new error_type(that.error())); return *this; } - inline enum type type() const + inline bool has_value() const { - return m_type; + return !!m_value; } - inline const std::unique_ptr& value() const + inline const value_type& value() const { - return m_value; + return *m_value; } - inline const std::unique_ptr& error() const + inline const error_type& error() const { - return m_error; + return *m_error; } inline explicit operator bool() const { - return m_type == type::ok; + return has_value(); } inline bool operator!() const { - return m_type == type::error; + return !has_value(); } inline bool equals(const result& that) const { - return m_type == that.m_type - && m_value == that.m_value - && m_error == that.m_error; + if (has_value()) + { + if (!that.has_value()) + { + return false; + } + + return *m_value == *that.m_value; + } + else if (that.has_value()) + { + return false; + } + + return *m_error == *that.m_error; } inline bool operator==(const result& that) const @@ -129,21 +132,45 @@ namespace peelo return !equals(that); } + template + inline bool equals(const result& that) const + { + if (has_value()) + { + if (!that.has_value()) + { + return false; + } + + return *m_value == that.value(); + } + else if (that.has_value()) + { + return false; + } + + return *m_error = that.error(); + } + + template + inline bool operator==(const result& that) const + { + return equals(that); + } + + template + inline bool operator!=(const result& that) const + { + return !equals(that); + } + private: - result( - enum type type, - value_type* value, - error_type* error - ) - : m_type(type) - , m_value(value) + result(value_type* value, error_type* error) + : m_value(value) , m_error(error) {} private: - enum type m_type; std::unique_ptr m_value; std::unique_ptr m_error; }; } - -#endif /* !PEELO_RESULT_HPP_GUARD */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3cbb579..65b5401 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,11 +17,19 @@ FOREACH(TEST_FILENAME ${TEST_SOURCES}) cxx_std_17 ) - TARGET_COMPILE_OPTIONS( - ${TEST_NAME} - PRIVATE - -Wall -Werror - ) + IF(MSVC) + TARGET_COMPILE_OPTIONS( + ${TEST_NAME} + PRIVATE + /W4 /WX + ) + ELSE() + TARGET_COMPILE_OPTIONS( + ${TEST_NAME} + PRIVATE + -Wall -Werror + ) + ENDIF() TARGET_LINK_LIBRARIES( ${TEST_NAME} diff --git a/test/test_result.cpp b/test/test_result.cpp index ffe2b3f..d36e49a 100644 --- a/test/test_result.cpp +++ b/test/test_result.cpp @@ -17,103 +17,98 @@ struct error using result = peelo::result; -static void test_ok() +static void +test_ok() { const result r = result::ok({ 5, "five" }); - assert(r.type() == result::type::ok); assert(bool(r) == true); assert(!r == false); - assert(bool(r.value()) == true); - assert(bool(r.error()) == false); - assert(r.value()->numeric == 5); - assert(r.value()->text == "five"); + assert(r.value().numeric == 5); + assert(r.value().text == "five"); } -static void test_error() +static void +test_error() { const result r = result::error({ 404, "Not Found" }); - assert(r.type() == result::type::error); assert(bool(r) == false); assert(!r == true); - assert(bool(r.value()) == false); - assert(bool(r.error()) == true); - assert(r.error()->code == 404); - assert(r.error()->message == "Not Found"); + assert(r.error().code == 404); + assert(r.error().message == "Not Found"); } -static void test_copy_ok() +static void +test_copy_ok() { const result original = result::ok({ 5, "Five" }); const result copy(original); - assert(copy.type() == original.type()); - assert(copy.value()->numeric == original.value()->numeric); - assert(!copy.error()); + assert(bool(copy) == bool(original)); + assert(copy.value().numeric == original.value().numeric); } -static void test_copy_error() +static void +test_copy_error() { const result original = result::error({ 404, "Not Found"}); const result copy(original); - assert(copy.type() == original.type()); - assert(copy.error()->code == original.error()->code); - assert(!copy.value()); + assert(bool(copy) == bool(original)); + assert(copy.error().code == original.error().code); } -static void test_copy_ok_with_different_types() +static void +test_copy_ok_with_different_types() { using result1 = peelo::result; using result2 = peelo::result; const result1 original = result1::ok(5); const result2 copy(original); - assert(copy.type() == result2::type::ok); - assert(*copy.value() == *original.value()); - assert(!copy.error()); + assert(bool(copy) == bool(original)); + assert(copy.value() == original.value()); } -static void test_copy_error_with_different_types() +static void +test_copy_error_with_different_types() { using result1 = peelo::result; using result2 = peelo::result; const result1 original = result1::error({ 404, "Not Found"}); const result2 copy(original); - assert(copy.type() == result2::type::error); - assert(copy.error()->code == original.error()->code); - assert(!copy.value()); + assert(!copy); + assert(copy.error().code == original.error().code); } -static void test_assign_ok() +static void +test_assign_ok() { const result ok = result::ok({ 5, "Five" }); result r = result::error({ 400, "Bad Request" }); r = ok; - assert(r.type() == ok.type()); - assert(bool(r.value())); - assert(!r.error()); - assert(r.value()->numeric == ok.value()->numeric); + assert(bool(r)); + assert(r.value().numeric == ok.value().numeric); } -static void test_assign_error() +static void +test_assign_error() { const result err = result::error({ 500, "Internal Server Error" }); result r = result::ok({ 1, "One"}); r = err; - assert(r.type() == err.type()); - assert(!r.value()); - assert(bool(r.error())); - assert(r.error()->code == err.error()->code); + assert(!r); + assert(r.error().code == err.error().code); } -static void test_assign_ok_with_different_types() +static void +test_assign_ok_with_different_types() { using result1 = peelo::result; using result2 = peelo::result; @@ -122,13 +117,12 @@ static void test_assign_ok_with_different_types() r = ok; - assert(r.type() == result2::type::ok); - assert(bool(r.value())); - assert(!r.error()); - assert(*r.value() == *ok.value()); + assert(bool(r)); + assert(r.value() == ok.value()); } -static void test_assign_error_with_different_types() +static void +test_assign_error_with_different_types() { using result1 = peelo::result; using result2 = peelo::result; @@ -137,18 +131,18 @@ static void test_assign_error_with_different_types() r = err; - assert(r.type() == result2::type::error); - assert(!r.value()); - assert(bool(r.error())); - assert(r.error()->code == err.error()->code); + assert(!r); + assert(r.error().code == err.error().code); } -static void test_equals() +static void +test_equals() { - const auto ok1 = result::ok({ 1, "One" }); - const auto ok2 = result::ok({ 2, "Two" }); - const auto err1 = result::error({ 401, "Unauthorized" }); - const auto err2 = result::error({ 418, "I'm a teapot" }); + using my_result = peelo::result; + const auto ok1 = my_result::ok(1); + const auto ok2 = my_result::ok(2); + const auto err1 = my_result::error("Unauthorized"); + const auto err2 = my_result::error("I'm a teapot"); assert(ok1 == ok1); assert(ok1 != ok2); @@ -156,7 +150,8 @@ static void test_equals() assert(err1 != err2); } -int main() +int +main() { test_ok(); test_error(); @@ -169,6 +164,4 @@ int main() test_assign_ok_with_different_types(); test_assign_error_with_different_types(); test_equals(); - - return 0; }