// https://github.com/kunitoki/LuaBridge3 // Copyright 2022, kunitoki // SPDX-License-Identifier: MIT #pragma once #include "Config.h" #include #include #include #include #if LUABRIDGE_HAS_EXCEPTIONS #include #endif namespace luabridge { namespace detail { using std::swap; template T* construct_at(T* ptr, Args&&... args) noexcept(std::is_nothrow_constructible::value) { return static_cast(::new (const_cast(static_cast(ptr))) T(std::forward(args)...)); } template struct is_swappable_with_impl : std::false_type { }; template struct is_swappable_with_impl(), std::declval()))>> : std::true_type { }; template struct is_nothrow_swappable_with_impl { static constexpr bool value = noexcept(swap(std::declval(), std::declval())) && noexcept(swap(std::declval(), std::declval())); using type = std::bool_constant; }; template struct is_swappable_with : std::conjunction< is_swappable_with_impl, std::add_lvalue_reference_t>, is_swappable_with_impl, std::add_lvalue_reference_t>>::type { }; template struct is_nothrow_swappable_with : std::conjunction, is_nothrow_swappable_with_impl>::type { }; template struct is_nothrow_swappable : std::is_nothrow_swappable_with, std::add_lvalue_reference_t> { }; template struct has_member_message : std::false_type { }; template struct has_member_message().message())>> : std::true_type { }; template inline static constexpr bool has_member_message_v = has_member_message::value; } // namespace detail template class Expected; struct UnexpectType { constexpr UnexpectType() = default; }; static constexpr auto unexpect = UnexpectType(); namespace detail { template , bool = (std::is_void_v || std::is_trivial_v) && std::is_trivial_v> union expected_storage { public: template >> constexpr expected_storage() noexcept : value_() { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: T value_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept(std::is_nothrow_default_constructible_v) : value_() { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() { } constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: T value_; E error_; }; template union expected_storage { public: constexpr explicit expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() { } constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; T value_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; E error_; }; template class expected_base_trivial { using this_type = expected_base_trivial; protected: using storage_type = expected_storage; constexpr expected_base_trivial() noexcept : valid_(true) { } template constexpr expected_base_trivial(std::in_place_t, Args&&... args) noexcept : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_trivial(UnexpectType, Args&&... args) noexcept : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_trivial(const expected_base_trivial& other) noexcept { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_trivial(expected_base_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_trivial() noexcept = default; constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept { } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_non_trivial(expected_base_non_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) = delete; expected_base_non_trivial(expected_base_non_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; template >> constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_non_trivial(expected_base_non_trivial&& other) = delete; ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; template >> constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) = delete; expected_base_non_trivial(expected_base_non_trivial&& other) = delete; ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template using expected_base = std::conditional_t< (std::is_void_v || std::is_trivially_destructible_v) && std::is_trivially_destructible_v, expected_base_trivial, expected_base_non_trivial>; } // namespace detail template class Unexpected { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); public: Unexpected() = delete; constexpr explicit Unexpected(E&& e) noexcept(std::is_nothrow_move_constructible_v) : error_(std::move(e)) { } constexpr explicit Unexpected(const E& e) noexcept(std::is_nothrow_copy_constructible_v) : error_(e) { } constexpr const E& value() const& noexcept { return error_; } constexpr E& value() & noexcept { return error_; } constexpr const E&& value() const&& noexcept { return std::move(error_); } constexpr E&& value() && noexcept { return std::move(error_); } private: E error_; }; template constexpr bool operator==(const Unexpected& lhs, const Unexpected& rhs) noexcept { return lhs.value() == rhs.value(); } template constexpr bool operator!=(const Unexpected& lhs, const Unexpected& rhs) noexcept { return lhs.value() != rhs.value(); } template constexpr inline Unexpected> makeUnexpected(E&& error) noexcept(std::is_nothrow_constructible_v>, E>) { return Unexpected>{ std::forward(error) }; } #if LUABRIDGE_HAS_EXCEPTIONS template class BadExpectedAccess; template <> class BadExpectedAccess : public std::runtime_error { template friend class BadExpectedAccess; BadExpectedAccess(std::in_place_t) noexcept : std::runtime_error("Bad access to expected value") { } public: BadExpectedAccess() noexcept : BadExpectedAccess(std::in_place) { } explicit BadExpectedAccess(const std::string& message) noexcept : std::runtime_error(message) { } }; template class BadExpectedAccess : public std::runtime_error { public: explicit BadExpectedAccess(E error) noexcept(std::is_nothrow_constructible_v) : std::runtime_error([](const E& error) { if constexpr (detail::has_member_message_v) return error.message(); else return "Bad access to expected value"; }(error)) , error_(std::move(error)) { } const E& error() const& noexcept { return error_; } E& error() & noexcept { return error_; } E&& error() && noexcept { return std::move(error_); } private: E error_; }; #endif namespace detail { template inline void throw_bad_expected_access_or_abort(E e) { #if LUABRIDGE_HAS_EXCEPTIONS throw BadExpectedAccess(std::move(e)); #else std::abort(); #endif } } // namespace detail template struct is_expected : std::false_type { }; template struct is_expected> : std::true_type { }; template struct is_unexpected : std::false_type { }; template struct is_unexpected> : std::true_type { }; template class Expected : public detail::expected_base, std::is_move_constructible_v> { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); using base_type = detail::expected_base, std::is_move_constructible_v>; using this_type = Expected; public: using value_type = T; using error_type = E; using unexpected_type = Unexpected; template struct rebind { using type = Expected; }; template >> constexpr Expected() noexcept(std::is_nothrow_default_constructible_v) : base_type() { } constexpr Expected(const Expected& other) noexcept(std::is_nothrow_copy_constructible_v) = default; constexpr Expected(Expected&& other) noexcept(std::is_nothrow_move_constructible_v) = default; template Expected(const Expected& other) { if (other.hasValue()) { this->construct(std::in_place, other.value()); } else { this->construct(unexpect, other.error()); } } template Expected(Expected&& other) { if (other.hasValue()) { this->construct(std::in_place, std::move(other.value())); } else { this->construct(unexpect, std::move(other.error())); } } template && std::is_constructible_v && !std::is_same_v, std::in_place_t> && !is_expected>::value && !is_unexpected>::value, int> = 0> constexpr Expected(U&& value) noexcept(std::is_nothrow_constructible_v) : base_type(std::in_place, std::forward(value)) { } template constexpr explicit Expected(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : base_type(std::in_place, std::forward(args)...) { } template constexpr explicit Expected(std::in_place_t, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) : base_type(std::in_place, ilist, std::forward(args)...) { } template constexpr Expected(const Unexpected& u) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, u.value()) { } template constexpr Expected(Unexpected&& u) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, std::move(u.value())) { } template constexpr explicit Expected(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, std::forward(args)...) { } template constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) : base_type(unexpect, ilist, std::forward(args)...) { } Expected& operator=(const Expected& other) { if (other.hasValue()) { assign(std::in_place, other.value()); } else { assign(unexpect, other.error()); } return *this; } Expected& operator=(Expected&& other) noexcept { if (other.hasValue()) { assign(std::in_place, std::move(other.value())); } else { assign(unexpect, std::move(other.error())); } return *this; } template >::value && !is_unexpected>::value, int> = 0> Expected& operator=(U&& value) { assign(std::in_place, std::forward(value)); return *this; } template Expected& operator=(const Unexpected& u) { assign(unexpect, u.value()); return *this; } template Expected& operator=(Unexpected&& u) { assign(unexpect, std::move(u.value())); return *this; } template T& emplace(Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, std::forward(args)...))) { return assign(std::in_place, std::forward(args)...); } template T& emplace(std::initializer_list ilist, Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, ilist, std::forward(args)...))) { return assign(std::in_place, ilist, std::forward(args)...); } void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value && detail::is_nothrow_swappable::value) { using std::swap; if (hasValue()) { if (other.hasValue()) { swap(value(), other.value()); } else { E error = std::move(other.error()); other.assign(std::in_place, std::move(value())); assign(unexpect, std::move(error)); } } else { if (other.hasValue()) { other.swap(*this); } else { swap(error(), other.error()); } } } constexpr const T* operator->() const { return base_type::valuePtr(); } constexpr T* operator->() { return base_type::valuePtr(); } constexpr const T& operator*() const& { return value(); } constexpr T& operator*() & { return value(); } constexpr const T&& operator*() const&& { return std::move(value()); } constexpr T&& operator*() && { return std::move(value()); } constexpr explicit operator bool() const noexcept { return hasValue(); } constexpr bool hasValue() const noexcept { return base_type::valid(); } constexpr const T& value() const& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return base_type::value(); } constexpr T& value() & LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return base_type::value(); } constexpr const T&& value() const&& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return std::move(base_type::value()); } constexpr T&& value() && LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return std::move(base_type::value()); } constexpr const E& error() const& noexcept { return base_type::error(); } constexpr E& error() & noexcept { return base_type::error(); } constexpr const E&& error() const&& noexcept { return std::move(base_type::error()); } constexpr E&& error() && noexcept { return std::move(base_type::error()); } template constexpr T valueOr(U&& defaultValue) const& { return hasValue() ? value() : static_cast(std::forward(defaultValue)); } template T valueOr(U&& defaultValue) && { return hasValue() ? std::move(value()) : static_cast(std::forward(defaultValue)); } private: template auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) -> decltype(std::declval().construct(tag, std::forward(args)...)) { this->destroy(); return this->construct(tag, std::forward(args)...); } }; template class Expected : public detail::expected_base, std::is_move_constructible_v> { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); using base_type = detail::expected_base, std::is_move_constructible_v>; using this_type = Expected; public: using value_type = void; using error_type = E; using unexpected_type = Unexpected; template struct rebind { using type = Expected; }; constexpr Expected() = default; constexpr Expected(const Expected& other) = default; constexpr Expected(Expected&& other) = default; template Expected(const Expected& other) { if (other.hasValue()) { this->valid_ = true; } else { this->construct(unexpect, other.error()); } } template Expected(Expected&& other) { if (other.hasValue()) { this->valid_ = true; } else { this->construct(unexpect, std::move(other.error())); } } template constexpr Expected(const Unexpected& u) : base_type(unexpect, u.value()) { } template constexpr Expected(Unexpected&& u) : base_type(unexpect, std::move(u.value())) { } template constexpr explicit Expected(UnexpectType, Args&&... args) : base_type(unexpect, std::forward(args)...) { } template constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) : base_type(unexpect, ilist, std::forward(args)...) { } Expected& operator=(const Expected& other) { if (other.hasValue()) { assign(std::in_place); } else { assign(unexpect, other.error()); } return *this; } Expected& operator=(Expected&& other) { if (other.hasValue()) { assign(std::in_place); } else { assign(unexpect, std::move(other.error())); } return *this; } template Expected& operator=(const Unexpected& u) { assign(unexpect, u.value()); return *this; } template Expected& operator=(Unexpected&& u) { assign(unexpect, std::move(u.value())); return *this; } void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value) { using std::swap; if (hasValue()) { if (!other.hasValue()) { assign(unexpect, std::move(other.error())); other.assign(std::in_place); } } else { if (other.hasValue()) { other.swap(*this); } else { swap(error(), other.error()); } } } constexpr explicit operator bool() const noexcept { return hasValue(); } constexpr bool hasValue() const noexcept { return base_type::valid(); } constexpr const E& error() const& noexcept { return base_type::error(); } constexpr E& error() & noexcept { return base_type::error(); } constexpr const E&& error() const&& noexcept { return std::move(base_type::error()); } constexpr E&& error() && noexcept { return std::move(base_type::error()); } private: template void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) { this->destroy(); this->construct(tag, std::forward(args)...); } }; template constexpr bool operator==(const Expected& lhs, const Expected& rhs) { return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } template constexpr bool operator==(const Expected& lhs, const Expected& rhs) { return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } template constexpr bool operator!=(const Expected& lhs, const Expected& rhs) { return !(lhs == rhs); } template constexpr bool operator==(const Expected& lhs, const T& rhs) { return lhs ? *lhs == rhs : false; } template constexpr bool operator==(const T& lhs, const Expected& rhs) { return rhs == lhs; } template constexpr bool operator!=(const Expected& lhs, const T& rhs) { return !(lhs == rhs); } template constexpr bool operator!=(const T& lhs, const Expected& rhs) { return rhs != lhs; } template constexpr bool operator==(const Expected& lhs, const Unexpected& rhs) { return lhs ? false : lhs.error() == rhs.value(); } template constexpr bool operator==(const Unexpected& lhs, const Expected& rhs) { return rhs == lhs; } template constexpr bool operator!=(const Expected& lhs, const Unexpected& rhs) { return !(lhs == rhs); } template constexpr bool operator!=(const Unexpected& lhs, const Expected& rhs) { return rhs != lhs; } } // namespace luabridge