#pragma once #include "../DefaultInclude.hpp" #include #include #include #include // clang-format off namespace geode { namespace { struct AnyType { explicit AnyType() = delete; }; template concept ConvertibleToResult = std::is_convertible_v, std::remove_reference_t> || std::is_same_v, std::remove_reference_t>; using DefaultValue = std::monostate; using DefaultError = std::string; template struct Storage { std::variant m_value; bool holdsOk() const { return std::holds_alternative(m_value); } T getOk() const requires std::is_copy_constructible_v { return std::get(m_value); } T&& getOk() requires(!std::is_copy_constructible_v) { return std::move(std::get(m_value)); } E getErr() const requires std::is_copy_constructible_v { return std::get(m_value); } E&& getErr() requires(!std::is_copy_constructible_v) { return std::move(std::get(m_value)); } template requires std::is_convertible_v && std::is_convertible_v Storage(Storage const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v { if (other.holdsOk()) { m_value = other.getOk(); } else { m_value = other.getErr(); } } Storage(T const& value) requires std::is_copy_constructible_v : m_value(value) {} Storage(T&& value) requires std::is_move_constructible_v : m_value(std::forward(value)) {} Storage(E const& value, std::monostate) requires std::is_copy_constructible_v : m_value(value) {} Storage(E&& value, std::monostate) requires std::is_move_constructible_v : m_value(std::forward(value)) {} }; template struct Storage { bool m_holdsOk; T m_value; bool holdsOk() const { return m_holdsOk; } T getOk() const requires std::is_copy_constructible_v { return m_value; } T&& getOk() requires(!std::is_copy_constructible_v) { return std::move(m_value); } T getErr() const requires std::is_copy_constructible_v { return m_value; } T&& getErr() requires(!std::is_copy_constructible_v) { return std::move(m_value); } template requires std::is_convertible_v && std::is_convertible_v Storage(Storage const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v : m_value(other.holdsOk() ? other.getOk() : other.getErr()), m_holdsOk(other.holdsOk()) {} Storage(T const& value) requires std::is_copy_constructible_v : m_value(value), m_holdsOk(true) {} Storage(T&& value) requires std::is_move_constructible_v : m_value(std::forward(value)), m_holdsOk(true) {} Storage(T const& value, std::monostate) requires std::is_copy_constructible_v : m_value(value), m_holdsOk(false) {} Storage(T&& value, std::monostate) requires std::is_move_constructible_v : m_value(std::forward(value)), m_holdsOk(false) {} }; } template class [[nodiscard]] Result final { public: using value_type = std::remove_reference_t; using error_type = std::remove_reference_t; // for some reason doing requires causes errors with pch... static_assert( std::is_copy_constructible_v || std::is_move_constructible_v, "T must be copiable or movable!" ); static_assert( std::is_copy_constructible_v || std::is_move_constructible_v, "E must be copiable or movable!" ); protected: Storage m_value; public: Storage const& _Raw_Storage() const { return m_value; } bool isOk() const { return m_value.holdsOk(); } bool isErr() const { return !m_value.holdsOk(); } template Result expect(const char* str, Args&&... args) { if (isErr()) { return Result(fmt::format( str, std::forward(args)..., fmt::arg("error", unwrapErr()) ), std::monostate()); } else { return *this; } } explicit Result(value_type const& value) requires std::is_copy_constructible_v : m_value(value) {} explicit Result(value_type&& value) requires std::is_move_constructible_v : m_value(std::forward(value)) {} explicit Result(error_type const& value, std::monostate) requires std::is_copy_constructible_v : m_value(value, std::monostate()) {} explicit Result(error_type&& value, std::monostate) requires std::is_move_constructible_v : m_value(std::forward(value), std::monostate()) {} Result(Result const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v = default; Result(Result&& other) requires( !std::is_copy_constructible_v || !std::is_copy_constructible_v ) = default; template requires std::is_convertible_v && std::is_convertible_v Result(Result const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v : m_value(other._Raw_Storage()) {} template requires ConvertibleToResult Result(Result const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v : Result(value_type(other.unwrap())) {} template requires ConvertibleToResult Result(Result const& other) requires std::is_copy_constructible_v && std::is_copy_constructible_v : m_value(std::forward(other.unwrapErr()), std::monostate()) {} template requires ConvertibleToResult Result(Result&& other) requires( !std::is_copy_constructible_v || !std::is_copy_constructible_v ) : m_value(other.unwrap()) {} template requires ConvertibleToResult Result(Result&& other) requires( !std::is_copy_constructible_v || !std::is_copy_constructible_v ) : Result(std::forward(other.unwrapErr()), std::monostate()) {} value_type unwrap() const requires std::is_copy_constructible_v { return m_value.getOk(); } value_type&& unwrap() requires(!std::is_copy_constructible_v) { return std::forward(m_value.getOk()); } error_type unwrapErr() const requires std::is_copy_constructible_v { return m_value.getErr(); } error_type&& unwrapErr() requires(!std::is_copy_constructible_v) { return std::forward(m_value.getErr()); } explicit operator bool() const requires( !std::is_same_v && !std::is_same_v ) { return this->isOk(); } }; template requires std::is_copy_constructible_v Result Ok(T value = T()) { return Result(value); } template requires(!std::is_copy_constructible_v) Result Ok(T&& value) { return Result(std::forward(value)); } template requires std::is_copy_constructible_v Result Err(E error) { return Result(error, std::monostate()); } template requires(!std::is_copy_constructible_v) Result Err(E&& error) { return Result(std::forward(error), std::monostate()); } #define GEODE_UNWRAP_INTO(into, ...) \ auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \ if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \ return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \ } \ into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap()) #define GEODE_UNWRAP(...) \ { \ auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \ if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \ return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \ } \ } } // clang-format on