#ifndef QUERY_RESULT_HPP #define QUERY_RESULT_HPP #include #include #include #include namespace matador::utils { template < typename ValueType, typename ErrorType > class [[nodiscard]] result; template struct is_result : std::false_type {}; template < typename ValueType, typename ErrorType > struct is_result> : std::true_type {}; template < typename ValueType > class ok { public: using value_type = ValueType; explicit constexpr ok(const ValueType &value) : value_(value) {} explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {} constexpr ValueType&& release() { return std::move(value_); } const ValueType& value() const { return value_; } ValueType& value() { return value_; } private: ValueType value_; }; template <> class ok { public: using value_type = void; explicit constexpr ok() = default; }; template < typename ErrorType > class failure { public: using value_type = ErrorType; explicit constexpr failure(const ErrorType &error) : error_(error) {} explicit constexpr failure(ErrorType &&error) : error_(std::move(error)) {} constexpr ErrorType&& release() { return std::move(error_); } const ErrorType& value() const { return error_; } ErrorType value() { return error_; } private: ErrorType error_; }; template < typename ValueType, typename ErrorType > class result { public: using value_type = ValueType; using error_type = ErrorType; result() : result_(ValueType{}) {} result(ok value) : result_(std::move(value.release())) {} // NOLINT(*-explicit-constructor) result(failure error) : result_(std::move(error.release())) {} // NOLINT(*-explicit-constructor) result(const result &x) = default; result& operator=(const result &x) = default; result(result &&x) = default; result& operator=(result &&x) = default; operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor) [[nodiscard]] bool is_ok() const { return std::holds_alternative(result_); } [[nodiscard]] bool is_error() const { return std::holds_alternative(result_); } ValueType&& release() { return std::move(std::get(result_)); } ErrorType&& release_error() { return std::move(std::get(result_)); } const ValueType& value() const { return std::get(result_); } ValueType& value() { return std::get(result_); } const ErrorType& err() const { return std::get(result_); } ErrorType err() { return std::get(result_); } constexpr const ValueType* operator->() const { return &value(); } constexpr ValueType* operator->() { return &std::get(result_); } constexpr const ValueType& operator*() const& noexcept { return value(); } constexpr ValueType& operator*() & noexcept { return value(); } template> result map(Func &&f) { if (is_ok()) { return result(ok(f(release()))); } return result(failure(release_error())); } template::value_type> result map_error(Func &&f) { if (!is_ok()) { return result(ok(release())); } return result(error(release_error())); } template::value_type> result and_then(Func &&f) { if (is_ok()) { return f(release()); } return result(failure(release_error())); } template::value_type> result or_else(Func &&f) { if (is_error()) { return f(err()); } return result(ok(release())); } private: std::variant result_; }; template < typename ErrorType > class result { public: using value_type = void; using error_type = ErrorType; result() = default; result(ok /*value*/) {} result(failure error) : result_(std::move(error.release())) {} // NOLINT(*-explicit-constructor) result(const result &x) = default; result& operator=(const result &x) = default; result(result &&x) = default; result& operator=(result &&x) = default; operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor) [[nodiscard]] bool is_ok() const { return !result_.has_value(); } [[nodiscard]] bool is_error() const { return result_.has_value(); } ErrorType&& release_error() { return std::move(*result_); } const ErrorType& err() const { return result_.value(); } ErrorType err() { return result_.value(); } template> result map(Func &&f) { if (is_ok()) { return result(ok(f())); } return result(failure(release_error())); } template result and_then(Func &&f) { if (is_ok()) { return f(); } return result(failure(release_error())); } template::value_type> result or_else(Func &&f) { if (is_error()) { return f(err()); } return result(ok()); } private: std::optional result_; }; } #endif //QUERY_RESULT_HPP