#pragma once #include "../DefaultInclude.hpp" #include "../external/result/result.hpp" #include #include #include #include #include #include namespace geode { namespace impl { using DefaultValue = std::monostate; using DefaultError = std::string; template using WrappedResult = std::conditional_t< std::is_lvalue_reference_v, std::reference_wrapper>, std::remove_const_t>; template class [[nodiscard]] Failure { public: WrappedResult m_error; Failure() = default; template requires(std::is_constructible_v) explicit constexpr Failure(E2 const& e) : m_error(e) {} template requires(std::is_constructible_v) explicit constexpr Failure(E2&& e) : m_error(std::move(e)) {} E& error() & noexcept { return m_error; } E const& error() const& noexcept { return m_error; } E&& error() && noexcept { return static_cast(m_error); } E const&& error() const&& noexcept { return static_cast(m_error); } }; template class [[nodiscard]] Success { public: WrappedResult m_value; Success() = default; template requires(std::is_constructible_v) explicit constexpr Success(T2 const& v) : m_value(v) {} template requires(std::is_constructible_v) explicit constexpr Success(T2&& v) : m_value(std::forward(v)) {} T& value() & noexcept { return m_value; } T const& value() const& noexcept { return m_value; } T&& value() && noexcept { return static_cast(m_value); } T const&& value() const&& noexcept { return static_cast(m_value); } }; } template class [[nodiscard]] Result : public cpp::result { public: using Base = cpp::result; using ValueType = typename Base::value_type; using ErrorType = typename Base::error_type; using Base::result; template requires(cpp::detail::result_is_implicit_value_convertible::value) constexpr Result(U&& value) = delete; template requires(std::is_constructible_v) constexpr Result(impl::Failure const& e) : Base(cpp::failure(e.error())) {} template requires(std::is_constructible_v) constexpr Result(impl::Failure&& e) : Base(cpp::failure(std::move(e.error()))) {} template requires(std::is_constructible_v) constexpr Result(impl::Success const& s) : Base(s.value()) {} template requires(std::is_constructible_v) constexpr Result(impl::Success&& s) : Base(std::move(s.value())) {} [[nodiscard]] constexpr explicit operator bool() const noexcept { return this->Base::operator bool(); } [[nodiscard]] constexpr bool isOk() const noexcept { return this->Base::has_value(); } [[nodiscard]] constexpr bool isErr() const noexcept { return this->Base::has_error(); } [[nodiscard]] constexpr decltype(auto) unwrap() & { return this->Base::value(); } [[nodiscard]] constexpr decltype(auto) unwrap() const& { return this->Base::value(); } [[nodiscard]] constexpr decltype(auto) unwrap() && { return this->Base::value(); } [[nodiscard]] constexpr decltype(auto) unwrap() const&& { return this->Base::value(); } [[nodiscard]] constexpr decltype(auto) unwrapErr() & { return this->Base::error(); } [[nodiscard]] constexpr decltype(auto) unwrapErr() const& { return this->Base::error(); } [[nodiscard]] constexpr decltype(auto) unwrapErr() && { return this->Base::error(); } [[nodiscard]] constexpr decltype(auto) unwrapErr() const&& { return this->Base::error(); } template requires(std::is_constructible_v) [[nodiscard]] Result expect(std::string const& format, Args&&... args) { if (this->isErr()) { return impl::Failure(fmt::format( fmt::runtime(format), std::forward(args)..., fmt::arg("error", this->unwrapErr()) )); } else { return std::move(*this); } } template requires(std::is_constructible_v) [[nodiscard]] Result expect(std::string const& format, Args&&... args) const { if (this->isErr()) { return impl::Failure(fmt::format( fmt::runtime(format), std::forward(args)..., fmt::arg("error", this->unwrapErr()) )); } else { return *this; } } template [[nodiscard]] constexpr decltype(auto) unwrapOr(U&& val) && { return this->Base::value_or(std::forward(val)); } template [[nodiscard]] constexpr decltype(auto) unwrapOr(U&& val) const& { return this->Base::value_or(std::forward(val)); } template [[nodiscard]] constexpr decltype(auto) errorOr(U&& val) && { return this->Base::error_or(std::forward(val)); } template [[nodiscard]] constexpr decltype(auto) errorOr(U&& val) const& { return this->Base::error_or(std::forward(val)); } /** * Convert the result into an optional containing the value if Ok, and * nullopt if Err */ [[nodiscard]] constexpr std::optional ok() const& { if (this->isOk()) { return this->unwrap(); } return std::nullopt; } /** * Convert the result into an optional containing the value if Ok, and * nullopt if Err */ [[nodiscard]] constexpr std::optional ok() && { if (this->isOk()) { return this->unwrap(); } return std::nullopt; } /** * Convert the result into an optional containing the error if Err, and * nullopt if Ok */ [[nodiscard]] constexpr std::optional err() const& { if (this->isErr()) { return this->unwrapErr(); } return std::nullopt; } /** * Convert the result into an optional containing the error if Err, and * nullopt if Ok */ [[nodiscard]] constexpr std::optional err() && { if (this->isErr()) { return this->unwrapErr(); } return std::nullopt; } }; template constexpr impl::Success Ok() { return impl::Success(); } template constexpr impl::Success Ok(T value) { // DO NOT MAKE THE PARAMETER T&&!!!! THAT WILL CAUSE C++ TO DO UNEXPECTED // IMPLICIT MOVES FOR EXAMPLE WHEN DOING `Ok(unordered_map.at(value))` return impl::Success(std::forward(value)); } template constexpr impl::Failure Err(E error) { return impl::Failure(std::forward(error)); } template inline impl::Failure Err(std::string const& format, Args&&... args) { return impl::Failure( fmt::format(fmt::runtime(format), std::forward(args)...) ); } #define GEODE_UNWRAP_INTO(into, ...) \ auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \ if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \ return geode::Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \ } \ into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap()) #define GEODE_UNWRAP(...) \ do { \ auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \ if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \ return geode::Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \ } \ } while(false) }