aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/expected.hpp227
2 files changed, 228 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6326c05..86de9c9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,7 @@ set(WANDA_CORE_HEADERS
"src/control_connection.hpp"
"src/deferred_failure.hpp"
"src/environment.hpp"
+ "src/expected.hpp"
"src/keyed.hpp"
"src/message.hpp"
"src/optional.hpp"
diff --git a/src/expected.hpp b/src/expected.hpp
new file mode 100644
index 0000000..8cacefe
--- /dev/null
+++ b/src/expected.hpp
@@ -0,0 +1,227 @@
+#ifndef WANDA_EXPECTED_HPP
+#define WANDA_EXPECTED_HPP
+
+#include <initializer_list>
+#include <type_traits>
+#include <utility>
+
+namespace wanda
+{
+
+template <typename ErrorType>
+struct unexpected
+{
+ static_assert(!std::is_same_v<ErrorType, void>, "ErrorType can not be 'void'!");
+ static_assert(!std::is_array_v<ErrorType>, "ErrorType can not be an array type!");
+
+ /**
+ * @brief Copy construct a new @p unexpected from another @p unexpected
+ */
+ constexpr unexpected(unexpected const &) = default;
+
+ /**
+ * @brief Move construct a new @p unexpected from another @p unexpected
+ */
+ constexpr unexpected(unexpected &&) = default;
+
+ /**
+ * @brief Construct a new @p unexpected by direct initializing the error object from @p args
+ */
+ template <typename... Args>
+ constexpr explicit unexpected(std::in_place_t, Args &&... args) : m_error(std::forward<Args>(args)...) {}
+
+ /**
+ * @brief Construct a new @p unexpected by direct initializing the error object from @p il and @p args
+ */
+ template <
+ typename U,
+ typename... Args,
+ std::enable_if_t<std::is_constructible_v<ErrorType, std::initializer_list<U>, Args...>> * = nullptr>
+ constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args &&... args) : m_error(il, std::forward<Args>(args)...) {}
+
+ /**
+ * @brief Construct a new @p unexpected by direct initializing the error object from @p error
+ */
+ template <
+ typename Err = ErrorType,
+ std::enable_if_t<std::is_constructible_v<ErrorType, Err> &&
+ !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Err>>, std::in_place_t> &&
+ !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Err>>, unexpected>> * = nullptr>
+ constexpr explicit unexpected(Err &&error) : m_error(std::forward<Err>(error)) {}
+
+ /**
+ * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type
+ */
+ template <
+ typename Err,
+ std::enable_if_t<!(
+ std::is_constructible_v<ErrorType, Err> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err>> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const> &&
+ !std::is_convertible_v<unexpected<Err> &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err>, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const, ErrorType>)> * = nullptr,
+ std::enable_if_t<!std::is_convertible_v<Err, ErrorType>> * = nullptr>
+ constexpr explicit unexpected(unexpected<Err> const &error) : m_error(error.m_error) {}
+
+ /**
+ * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type
+ */
+ template <
+ typename Err,
+ std::enable_if_t<!(
+ std::is_constructible_v<ErrorType, Err> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err>> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const> &&
+ !std::is_convertible_v<unexpected<Err> &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err>, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const, ErrorType>)> * = nullptr,
+ std::enable_if_t<std::is_convertible_v<Err, ErrorType>> * = nullptr>
+ constexpr unexpected(unexpected<Err> const &error) : m_error(error.m_error) {}
+
+ /**
+ * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type
+ */
+ template <
+ typename Err,
+ std::enable_if_t<!(
+ std::is_constructible_v<ErrorType, Err> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err>> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const> &&
+ !std::is_convertible_v<unexpected<Err> &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err>, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const, ErrorType>)> * = nullptr,
+ std::enable_if_t<!std::is_convertible_v<Err, ErrorType>> * = nullptr>
+ constexpr explicit unexpected(unexpected<Err> &&error) : m_error(std::move(error.m_error)) {}
+
+ /**
+ * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type
+ */
+ template <
+ typename Err,
+ std::enable_if_t<!(
+ std::is_constructible_v<ErrorType, Err> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err>> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const &> &&
+ !std::is_constructible_v<ErrorType, unexpected<Err> const> &&
+ !std::is_convertible_v<unexpected<Err> &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err>, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const &, ErrorType> &&
+ !std::is_convertible_v<unexpected<Err> const, ErrorType>)> * = nullptr,
+ std::enable_if_t<std::is_convertible_v<Err, ErrorType>> * = nullptr>
+ constexpr unexpected(unexpected<Err> &&error) : m_error(std::move(error.m_error)) {}
+
+ /**
+ * @brief Get the error value contained in this @p unexpected instance
+ */
+ constexpr ErrorType const &value() const &
+ {
+ return m_error;
+ }
+
+ /**
+ * @brief Get the error value contained in this @p unexpected instance
+ */
+ constexpr ErrorType &value() &
+ {
+ return m_error;
+ }
+
+ /**
+ * @brief Get the error value contained in this @p unexpected instance
+ */
+ constexpr ErrorType &&value() &&
+ {
+ return std::move(m_error);
+ }
+
+ /**
+ * @brief Get the error value contained in this @p unexpected instance
+ */
+ constexpr ErrorType const &&value() const &&
+ {
+ return std::move(m_error);
+ }
+
+ /**
+ * @brief Swap the error value of this @p unexpected instance with the one of @p other
+ */
+ void swap(unexpected &other) noexcept(std::is_nothrow_swappable_v<ErrorType>)
+ {
+ using std::swap;
+ swap(m_error, other.m_error);
+ }
+
+ template <typename ErrorType1, typename ErrorType2>
+ friend constexpr bool operator==(unexpected<ErrorType1> const &lhs, unexpected<ErrorType2> const &rhs);
+
+ template <typename ErrorType1, typename ErrorType2>
+ friend constexpr bool operator!=(unexpected<ErrorType1> const &lhs, unexpected<ErrorType2> const &rhs);
+
+ template <
+ typename Err,
+ std::enable_if_t<std::is_swappable_v<Err>> *>
+ friend void swap(unexpected<Err> &lhs, unexpected<Err> &rhs);
+
+ private:
+ ErrorType m_error;
+};
+
+template <typename ErrorType>
+unexpected(ErrorType)->unexpected<ErrorType>;
+
+/**
+ * @brief Compare two @p unexpected instances for equality
+ */
+template <typename ErrorType1, typename ErrorType2>
+constexpr bool operator==(unexpected<ErrorType1> const &lhs, unexpected<ErrorType2> const &rhs)
+{
+ return lhs.m_error == rhs.m_error;
+}
+
+/**
+ * @brief Compare two @p unexpected instances for inequality
+ */
+template <typename ErrorType1, typename ErrorType2>
+constexpr bool operator!=(unexpected<ErrorType1> const &lhs, unexpected<ErrorType2> const &rhs)
+{
+ return lhs.m_error != rhs.m_error;
+}
+
+/**
+ * @brief Swap the error values of two @p unexpected instances
+ */
+template <
+ typename Err,
+ std::enable_if_t<std::is_swappable_v<Err>> * = nullptr>
+void swap(unexpected<Err> &lhs, unexpected<Err> &rhs)
+{
+ lhs.swap(rhs);
+}
+
+/**
+ * @brief A tag type for @p unexpected
+ */
+struct unexpect_t
+{
+ explicit unexpect_t() = default;
+};
+
+/**
+ * @brief A tap for @p unexpected
+ */
+inline constexpr unexpect_t unexpect{};
+
+} // namespace wanda
+
+#endif \ No newline at end of file