|
|
|
|
@ -2,7 +2,6 @@
|
|
|
|
|
#define QUERY_RESULT_HPP
|
|
|
|
|
|
|
|
|
|
#include <variant>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
|
|
@ -21,6 +20,7 @@ template < typename ValueType >
|
|
|
|
|
class ok {
|
|
|
|
|
public:
|
|
|
|
|
using value_type = ValueType;
|
|
|
|
|
constexpr ok() = default;
|
|
|
|
|
explicit constexpr ok(const ValueType &value) : value_(value) {}
|
|
|
|
|
explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {}
|
|
|
|
|
|
|
|
|
|
@ -55,15 +55,43 @@ private:
|
|
|
|
|
ErrorType error_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
template <typename ValueType, typename Func, bool IsVoidValue = std::is_void_v<ValueType>>
|
|
|
|
|
struct map_result_value_type;
|
|
|
|
|
|
|
|
|
|
template <typename ValueType, typename Func>
|
|
|
|
|
struct map_result_value_type<ValueType, Func, false> {
|
|
|
|
|
using type = std::invoke_result_t<Func, ValueType&&>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename ValueType, typename Func>
|
|
|
|
|
struct map_result_value_type<ValueType, Func, true> {
|
|
|
|
|
using type = std::invoke_result_t<Func>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename ValueType, typename Func, bool IsVoidValue = std::is_void_v<ValueType>>
|
|
|
|
|
struct and_then_result_type;
|
|
|
|
|
|
|
|
|
|
template <typename ValueType, typename Func>
|
|
|
|
|
struct and_then_result_type<ValueType, Func, false> {
|
|
|
|
|
using type = std::invoke_result_t<Func, ValueType&&>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename ValueType, typename Func>
|
|
|
|
|
struct and_then_result_type<ValueType, Func, true> {
|
|
|
|
|
using type = std::invoke_result_t<Func>;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template < typename ValueType, typename ErrorType >
|
|
|
|
|
class result {
|
|
|
|
|
public:
|
|
|
|
|
using value_type = ValueType;
|
|
|
|
|
using error_type = ErrorType;
|
|
|
|
|
|
|
|
|
|
result() : result_(ValueType{}) {}
|
|
|
|
|
result(ok<value_type> value) : result_(std::move(value.release())) {} // NOLINT(*-explicit-constructor)
|
|
|
|
|
result(failure<error_type> error) : result_(std::move(error.release())) {} // NOLINT(*-explicit-constructor)
|
|
|
|
|
result() : result_(ok<value_type>{}) {}
|
|
|
|
|
result(ok<value_type> value) : result_(std::move(value)) {} // NOLINT(*-explicit-constructor)
|
|
|
|
|
result(failure<error_type> error) : result_(std::move(error)) {} // NOLINT(*-explicit-constructor)
|
|
|
|
|
result(const result &x) = default;
|
|
|
|
|
result& operator=(const result &x) = default;
|
|
|
|
|
result(result &&x) = default;
|
|
|
|
|
@ -71,31 +99,76 @@ public:
|
|
|
|
|
|
|
|
|
|
operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor)
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool is_ok() const { return std::holds_alternative<value_type>(result_); }
|
|
|
|
|
[[nodiscard]] bool is_error() const { return std::holds_alternative<error_type>(result_); }
|
|
|
|
|
|
|
|
|
|
ValueType&& release() { return std::move(std::get<value_type>(result_)); }
|
|
|
|
|
ErrorType&& release_error() { return std::move(std::get<error_type>(result_)); }
|
|
|
|
|
|
|
|
|
|
const ValueType& value() const { return std::get<value_type>(result_); }
|
|
|
|
|
ValueType& value() { return std::get<value_type>(result_); }
|
|
|
|
|
const ErrorType& err() const { return std::get<error_type>(result_); }
|
|
|
|
|
ErrorType& err() { return std::get<error_type>(result_); }
|
|
|
|
|
|
|
|
|
|
constexpr const ValueType* operator->() const { return &value(); }
|
|
|
|
|
constexpr ValueType* operator->() { return &std::get<value_type>(result_); }
|
|
|
|
|
|
|
|
|
|
constexpr const ValueType& operator*() const& noexcept { return value(); }
|
|
|
|
|
constexpr ValueType& operator*() & noexcept { return value(); }
|
|
|
|
|
|
|
|
|
|
template<typename Func,
|
|
|
|
|
typename SecondValueType = std::invoke_result_t<Func, ValueType >>
|
|
|
|
|
result<SecondValueType, ErrorType> map(Func &&f) {
|
|
|
|
|
if (is_ok()) {
|
|
|
|
|
return result<SecondValueType, ErrorType>(ok(std::invoke(std::forward<Func>(f), release())));
|
|
|
|
|
[[nodiscard]] bool is_ok() const {
|
|
|
|
|
return std::holds_alternative<ok<value_type>>(result_);
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] bool is_error() const {
|
|
|
|
|
return std::holds_alternative<failure<error_type>>(result_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result<SecondValueType, ErrorType>(failure(release_error()));
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
std::enable_if_t<!std::is_void_v<T>, T&&> release() {
|
|
|
|
|
return std::move(std::get<ok<value_type>>(result_).release());
|
|
|
|
|
}
|
|
|
|
|
ErrorType&& release_error() {
|
|
|
|
|
return std::move(std::get<failure<error_type>>(result_).release());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
std::enable_if_t<!std::is_void_v<T>, const T&> value() const {
|
|
|
|
|
return std::get<ok<value_type>>(result_).value();
|
|
|
|
|
}
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
std::enable_if_t<!std::is_void_v<T>, T&> value() {
|
|
|
|
|
return std::get<ok<value_type>>(result_).value();
|
|
|
|
|
}
|
|
|
|
|
const ErrorType& err() const {
|
|
|
|
|
return std::get<failure<error_type>>(result_).value();
|
|
|
|
|
}
|
|
|
|
|
ErrorType& err() {
|
|
|
|
|
return std::get<failure<error_type>>(result_).value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
constexpr std::enable_if_t<!std::is_void_v<T>, const T*> operator->() const {
|
|
|
|
|
return &value();
|
|
|
|
|
}
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
constexpr std::enable_if_t<!std::is_void_v<T>, T*> operator->() {
|
|
|
|
|
return &value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
constexpr std::enable_if_t<!std::is_void_v<T>, const T&> operator*() const& noexcept {
|
|
|
|
|
return value();
|
|
|
|
|
}
|
|
|
|
|
template <typename T = ValueType>
|
|
|
|
|
constexpr std::enable_if_t<!std::is_void_v<T>, T&> operator*() & noexcept {
|
|
|
|
|
return value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Func,
|
|
|
|
|
typename SecondValueType = typename detail::map_result_value_type<ValueType, Func>::type>
|
|
|
|
|
result<SecondValueType, ErrorType> map(Func &&f) {
|
|
|
|
|
if (is_error()) {
|
|
|
|
|
return failure<ErrorType>(release_error());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_void_v<ValueType>) {
|
|
|
|
|
if constexpr (std::is_void_v<SecondValueType>) {
|
|
|
|
|
std::invoke(std::forward<Func>(f));
|
|
|
|
|
return ok<void>{};
|
|
|
|
|
} else {
|
|
|
|
|
return ok<SecondValueType>(std::invoke(std::forward<Func>(f)));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if constexpr (std::is_void_v<SecondValueType>) {
|
|
|
|
|
std::invoke(std::forward<Func>(f), release());
|
|
|
|
|
return ok<void>{};
|
|
|
|
|
} else {
|
|
|
|
|
return ok<SecondValueType>(std::invoke(std::forward<Func>(f), release()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Func,
|
|
|
|
|
@ -105,18 +178,27 @@ public:
|
|
|
|
|
return failure<SecondErrorType>{std::invoke(std::forward<Func>(f), release_error())};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_void_v<ValueType>) {
|
|
|
|
|
return ok<void>{};
|
|
|
|
|
} else {
|
|
|
|
|
return ok<ValueType>(release());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Func,
|
|
|
|
|
typename SecondValueType = typename std::invoke_result_t<Func, ValueType>::value_type>
|
|
|
|
|
result<SecondValueType, ErrorType> and_then(Func &&f) {
|
|
|
|
|
using ReturnResult = std::invoke_result_t<Func, ValueType>;
|
|
|
|
|
typename ReturnResult = typename detail::and_then_result_type<ValueType, Func>::type>
|
|
|
|
|
ReturnResult and_then(Func &&f) {
|
|
|
|
|
static_assert(is_result<ReturnResult>::value, "and_then() callback must return matador::utils::result");
|
|
|
|
|
|
|
|
|
|
if (is_ok()) {
|
|
|
|
|
if constexpr (std::is_void_v<ValueType>) {
|
|
|
|
|
return std::invoke(std::forward<Func>(f));
|
|
|
|
|
} else {
|
|
|
|
|
return std::invoke(std::forward<Func>(f), release());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ReturnResult(failure(release_error()));
|
|
|
|
|
return ReturnResult(failure<ErrorType>(release_error()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Func,
|
|
|
|
|
@ -129,69 +211,16 @@ public:
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result<ValueType, SecondErrorType>(ok<ValueType>(release()));
|
|
|
|
|
if constexpr (std::is_void_v<ValueType>) {
|
|
|
|
|
return ok<void>{};
|
|
|
|
|
} else {
|
|
|
|
|
return ok<ValueType>(release());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::variant<value_type, error_type> result_;
|
|
|
|
|
std::variant<ok<value_type>, failure<error_type>> result_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template < typename ErrorType >
|
|
|
|
|
class result<void, ErrorType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using value_type = void;
|
|
|
|
|
using error_type = ErrorType;
|
|
|
|
|
|
|
|
|
|
result() = default;
|
|
|
|
|
result(ok<void> /*value*/) {}
|
|
|
|
|
result(failure<error_type> 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<typename Func, typename SecondValueType = std::invoke_result_t<Func>>
|
|
|
|
|
result<SecondValueType, ErrorType> map(Func &&f) {
|
|
|
|
|
if (is_ok()) {
|
|
|
|
|
return result<SecondValueType, ErrorType>(ok(f()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result<SecondValueType, ErrorType>(failure(release_error()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Func>
|
|
|
|
|
result and_then(Func &&f) {
|
|
|
|
|
if (is_ok()) {
|
|
|
|
|
return f();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result(failure(release_error()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Func, typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType&& >::value_type>
|
|
|
|
|
result<void, SecondErrorType> or_else(Func &&f) {
|
|
|
|
|
if (is_error()) {
|
|
|
|
|
return f(release_error());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result<void, SecondErrorType>(ok<void>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::optional<error_type> result_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif //QUERY_RESULT_HPP
|
|
|
|
|
|