#pragma once #include "../DefaultInclude.hpp" #include #include #include #include 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 class [[nodiscard]] Result { 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: std::variant m_value; public: bool isOk() const { return std::holds_alternative(m_value); } bool isErr() const { return std::holds_alternative(m_value); } template Result expect(const char* str, Args&&... args) { if (isErr()) { return Result(fmt::format(str, std::forward(args)...)); } 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 ) requires std::is_copy_constructible_v : m_value(value) {} explicit Result(error_type&& value) requires std::is_move_constructible_v : m_value(std::forward(value)) {} 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 ConvertibleToResult && ConvertibleToResult Result( Result const& other ) requires std::is_copy_constructible_v && std::is_copy_constructible_v { if (other.isOk()) { m_value = other.unwrap(); } else { m_value = other.unwrapErr(); } } template requires ConvertibleToResult && ConvertibleToResult Result( Result&& other ) requires(!std::is_copy_constructible_v || !std::is_copy_constructible_v) : m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {} 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())) {} 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())) {} value_type unwrap() const requires std::is_copy_constructible_v { return std::get(m_value); } value_type&& unwrap() requires(!std::is_copy_constructible_v) { return std::move(std::get(m_value)); } error_type unwrapErr() const requires std::is_copy_constructible_v { return std::get(m_value); } error_type&& unwrapErr() requires(!std::is_copy_constructible_v) { return std::move(std::get(m_value)); } explicit operator bool() const requires(!std::is_same_v && !std::is_same_v) { return this->isOk(); } }; template class [[nodiscard]] Result { 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!" ); protected: bool m_success; value_type m_value; public: bool isOk() const { return m_success; } bool isErr() const { return !m_success; } template Result expect(const char* str, Args&&... args) { if (isErr()) { return Result(fmt::format(str, std::forward(args)...), false); } else { return *this; } } explicit Result(value_type const& value, bool success) requires std::is_copy_constructible_v : m_value(value), m_success(success) {} explicit Result(value_type&& value, bool success) requires std::is_move_constructible_v : m_value(std::forward(value)), m_success(success) {} Result(Result const& other) requires std::is_copy_constructible_v = default; Result(Result&& other ) requires(!std::is_copy_constructible_v) = default; template requires ConvertibleToResult && ConvertibleToResult Result( Result const& other ) requires std::is_copy_constructible_v : m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {} template requires ConvertibleToResult && ConvertibleToResult Result( Result&& other ) requires(!std::is_copy_constructible_v) : m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {} template requires ConvertibleToResult Result(Result const& other) requires std::is_copy_constructible_v : Result(value_type(other.unwrap()), true) {} template requires ConvertibleToResult Result(Result&& other) requires(!std::is_copy_constructible_v) : Result(std::forward(other.unwrap()), true) {} template requires ConvertibleToResult Result(Result const& other) requires std::is_copy_constructible_v : Result(error_type(other.unwrapErr()), false) {} template requires ConvertibleToResult Result(Result&& other) requires(!std::is_copy_constructible_v) : Result(std::forward(other.unwrapErr()), false) {} value_type unwrap() const requires std::is_copy_constructible_v { return m_value; } value_type&& unwrap() requires(!std::is_copy_constructible_v) { return std::move(m_value); } error_type unwrapErr() const requires std::is_copy_constructible_v { return m_value; } error_type&& unwrapErr() requires(!std::is_copy_constructible_v) { return std::move(m_value); } explicit operator bool() const requires(!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 = E()) { return Result(error); } template requires(!std::is_copy_constructible_v) Result Err(E&& error) { return Result(std::forward(error)); } #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())); \ } \ } }