diff --git a/CMakeLists.txt b/CMakeLists.txt index 963be24f..e94e525f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,6 +237,7 @@ endif() set(MAT_JSON_AS_INTERFACE ON) CPMAddPackage("gh:geode-sdk/json#cda9807") +CPMAddPackage("gh:geode-sdk/result@1.0.1") CPMAddPackage("gh:fmtlib/fmt#10.2.1") target_compile_definitions(${PROJECT_NAME} INTERFACE MAT_JSON_DYNAMIC=1) @@ -296,7 +297,7 @@ target_include_directories(GeodeBindings PUBLIC ${GEODE_LOADER_PATH}/include/Geode/fmod ) target_link_directories(GeodeBindings PUBLIC ${GEODE_LOADER_PATH}/include/link) -target_link_libraries(GeodeBindings PUBLIC fmt TulipHookInclude mat-json) +target_link_libraries(GeodeBindings PUBLIC fmt TulipHookInclude mat-json GeodeResult) target_link_libraries(${PROJECT_NAME} INTERFACE GeodeBindings) if (NOT EXISTS ${GEODE_BIN_PATH}) diff --git a/loader/include/Geode/Utils.hpp b/loader/include/Geode/Utils.hpp index 5554a91f..c587c8d0 100644 --- a/loader/include/Geode/Utils.hpp +++ b/loader/include/Geode/Utils.hpp @@ -1,7 +1,6 @@ #pragma once #include "DefaultInclude.hpp" -#include "utils/Result.hpp" #include "utils/VersionInfo.hpp" #include "utils/ranges.hpp" #include "utils/casts.hpp" diff --git a/loader/include/Geode/external/result/result.hpp b/loader/include/Geode/external/result/result.hpp deleted file mode 100644 index f2ac2802..00000000 --- a/loader/include/Geode/external/result/result.hpp +++ /dev/null @@ -1,5994 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// \file result.hpp -/// -/// \brief This header contains the 'result' monadic type for indicating -/// possible error conditions -//////////////////////////////////////////////////////////////////////////////// - -/* - The MIT License (MIT) - - Copyright (c) 2017-2021 Matthew Rodusek All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#ifndef RESULT_RESULT_HPP -#define RESULT_RESULT_HPP - -#include // std::size_t -#include // std::enable_if, std::is_constructible, etc -#include // placement-new -#include // std::address_of -#include // std::reference_wrapper, std::invoke -#include // std::in_place_t, std::forward -#include // std::initializer_list -#include // std::string (for exception message) - -#if defined(RESULT_EXCEPTIONS_DISABLED) -# include // std::fprintf, stderr -#else -# include // std::logic_error -#endif - -#if __cplusplus >= 201402L -# define RESULT_CPP14_CONSTEXPR constexpr -#else -# define RESULT_CPP14_CONSTEXPR -#endif - -#if __cplusplus >= 201703L -# define RESULT_CPP17_INLINE inline -#else -# define RESULT_CPP17_INLINE -#endif - -#if defined(__clang__) && defined(_MSC_VER) -# define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden"))) -#elif defined(__clang__) || defined(__GNUC__) -# define RESULT_INLINE_VISIBILITY __attribute__((visibility("hidden"), always_inline)) -#elif defined(_MSC_VER) -# define RESULT_INLINE_VISIBILITY __forceinline -#else -# define RESULT_INLINE_VISIBILITY -#endif - -// [[clang::warn_unused_result]] is more full-featured than gcc's variant, since -// it supports being applied to class objects. -#if __cplusplus >= 201703L -# define RESULT_NODISCARD [[nodiscard]] -# define RESULT_WARN_UNUSED [[nodiscard]] -#elif defined(__clang__) && ((__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 9))) -# define RESULT_NODISCARD [[clang::warn_unused_result]] -# define RESULT_WARN_UNUSED [[clang::warn_unused_result]] -#elif defined(__GNUC__) -# define RESULT_NODISCARD -# define RESULT_WARN_UNUSED [[gnu::warn_unused_result]] -#else -# define RESULT_WARN_UNUSED -# define RESULT_NODISCARD -#endif - -#if defined(RESULT_NAMESPACE) -# define RESULT_NAMESPACE_INTERNAL RESULT_NAMESPACE -#else -# define RESULT_NAMESPACE_INTERNAL cpp -#endif -#define RESULT_NS_IMPL RESULT_NAMESPACE_INTERNAL::bitwizeshift - -// clang's `-Wdocumentation-unknown-command` flag is bugged and does not -// understand `\copydoc` tags, despite this being a valid doxygen tag. -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -#endif - -namespace RESULT_NAMESPACE_INTERNAL { -inline namespace bitwizeshift { - - //=========================================================================== - // utilities : constexpr forward - //=========================================================================== - - // std::forward is not constexpr until C++14 - namespace detail { -#if __cplusplus >= 201402L - using std::forward; -#else - template - inline RESULT_INLINE_VISIBILITY constexpr - auto forward(typename std::remove_reference::type& t) - noexcept -> T&& - { - return static_cast(t); - } - - template - inline RESULT_INLINE_VISIBILITY constexpr - auto forward(typename std::remove_reference::type&& t) - noexcept -> T&& - { - return static_cast(t); - } -#endif - } // namespace detail - - - //=========================================================================== - // utilities : invoke / invoke_result - //=========================================================================== - - // std::invoke was introduced in C++17 - - namespace detail { -#if __cplusplus >= 201703L - using std::invoke; - using std::invoke_result; - using std::invoke_result_t; -#else - template - struct is_reference_wrapper : std::false_type{}; - - template - struct is_reference_wrapper> : std::true_type{}; - - //------------------------------------------------------------------------- - - template ::value && - std::is_base_of::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmf, Derived&& ref, Args&&... args) - noexcept(noexcept((::RESULT_NS_IMPL::detail::forward(ref).*pmf)(::RESULT_NS_IMPL::detail::forward(args)...))) - -> decltype((::RESULT_NS_IMPL::detail::forward(ref).*pmf)(::RESULT_NS_IMPL::detail::forward(args)...)) - { - return (RESULT_NS_IMPL::detail::forward(ref).*pmf)(RESULT_NS_IMPL::detail::forward(args)...); - } - - template ::value && - is_reference_wrapper::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmf, RefWrap&& ref, Args&&... args) - noexcept(noexcept((ref.get().*pmf)(std::forward(args)...))) - -> decltype((ref.get().*pmf)(RESULT_NS_IMPL::detail::forward(args)...)) - { - return (ref.get().*pmf)(RESULT_NS_IMPL::detail::forward(args)...); - } - - template ::value && - !is_reference_wrapper::type>::value && - !std::is_base_of::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmf, Pointer&& ptr, Args&&... args) - noexcept(noexcept(((*std::forward(ptr)).*pmf)(std::forward(args)...))) - -> decltype(((*RESULT_NS_IMPL::detail::forward(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward(args)...)) - { - return ((*RESULT_NS_IMPL::detail::forward(ptr)).*pmf)(RESULT_NS_IMPL::detail::forward(args)...); - } - - template ::value && - std::is_base_of::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmd, Derived&& ref) - noexcept(noexcept(std::forward(ref).*pmd)) - -> decltype(RESULT_NS_IMPL::detail::forward(ref).*pmd) - { - return RESULT_NS_IMPL::detail::forward(ref).*pmd; - } - - template ::value && - is_reference_wrapper::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmd, RefWrap&& ref) - noexcept(noexcept(ref.get().*pmd)) - -> decltype(ref.get().*pmd) - { - return ref.get().*pmd; - } - - template ::value && - !is_reference_wrapper::type>::value && - !std::is_base_of::type>::value - >::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(T Base::*pmd, Pointer&& ptr) - noexcept(noexcept((*std::forward(ptr)).*pmd)) - -> decltype((*RESULT_NS_IMPL::detail::forward(ptr)).*pmd) - { - return (*RESULT_NS_IMPL::detail::forward(ptr)).*pmd; - } - - template ::type>::value>::type> - inline RESULT_INLINE_VISIBILITY constexpr - auto invoke(F&& f, Args&&... args) - noexcept(noexcept(std::forward(f)(std::forward(args)...))) - -> decltype(RESULT_NS_IMPL::detail::forward(f)(RESULT_NS_IMPL::detail::forward(args)...)) - { - return RESULT_NS_IMPL::detail::forward(f)(RESULT_NS_IMPL::detail::forward(args)...); - } - - template - struct is_invocable - { - template - static auto test( Fn2&&, Args2&&... ) - -> decltype(invoke(std::declval(), std::declval()...), std::true_type{}); - - static auto test(...) - -> std::false_type; - - using type = decltype(test(std::declval(), std::declval()...)); - static constexpr bool value = type::value; - }; - - template - struct invoke_result_impl { - using type = decltype(RESULT_NS_IMPL::detail::invoke(std::declval(), std::declval()...)); - }; - template - struct invoke_result_impl{}; - - template - struct invoke_result - : invoke_result_impl::value, Fn, Args...>{}; - - template - using invoke_result_t = typename invoke_result::type; -#endif - } - - //=========================================================================== - // struct : in_place_t - //=========================================================================== - -#if __cplusplus >= 201703L - using std::in_place_t; - using std::in_place; -#else - /// \brief A structure for representing in-place construction - struct in_place_t - { - explicit in_place_t() = default; - }; - RESULT_CPP17_INLINE constexpr auto in_place = in_place_t{}; -#endif - - //=========================================================================== - // struct : in_place_t - //=========================================================================== - - /// \brief A structure for representing in-place construction of an error type - struct in_place_error_t - { - explicit in_place_error_t() = default; - }; - - RESULT_CPP17_INLINE constexpr auto in_place_error = in_place_error_t{}; - - //=========================================================================== - // forward-declarations - //=========================================================================== - - template - class failure; - - template - class result; - - template - class bad_result_access; - - //=========================================================================== - // traits - //=========================================================================== - - template - struct is_failure : std::false_type{}; - template - struct is_failure> : std::true_type{}; - - template - struct is_result : std::false_type{}; - template - struct is_result> : std::true_type{}; - - //=========================================================================== - // trait : detail::wrapped_result_type - //=========================================================================== - - namespace detail { - - template - using wrapped_result_type = typename std::conditional< - std::is_lvalue_reference::value, - std::reference_wrapper< - typename std::remove_reference::type - >, - typename std::remove_const::type - >::type; - - } // namespace detail - -#if !defined(RESULT_DISABLE_EXCEPTIONS) - - //=========================================================================== - // class : bad_result_access - //=========================================================================== - - ///////////////////////////////////////////////////////////////////////////// - /// \brief An exception thrown when result::value is accessed without - /// a contained value - ///////////////////////////////////////////////////////////////////////////// - template - class bad_result_access : public std::logic_error - { - //------------------------------------------------------------------------- - // Constructor / Assignment - //------------------------------------------------------------------------- - public: - - /// \brief Constructs this exception using the underlying error type for - /// the error type - /// - /// \param error the underlying error - template ::value>::type> - explicit bad_result_access(E2&& error); - - /// \{ - /// \brief Constructs this exception using the underlying error type for - /// the error and a message - /// - /// \param what_arg the message for the failure - /// \param error the underlying error - template ::value>::type> - bad_result_access(const char* what_arg, E2&& error); - template ::value>::type> - bad_result_access(const std::string& what_arg, E2&& error); - /// \} - - bad_result_access(const bad_result_access& other) = default; - bad_result_access(bad_result_access&& other) = default; - - //------------------------------------------------------------------------- - - auto operator=(const bad_result_access& other) -> bad_result_access& = default; - auto operator=(bad_result_access&& other) -> bad_result_access& = default; - - /// \{ - /// \brief Gets the underlying error - /// - /// \return the error - auto error() & noexcept -> E&; - auto error() && noexcept -> E&&; - auto error() const & noexcept -> const E&; - auto error() const && noexcept -> const E&&; - /// \} - - //------------------------------------------------------------------------- - // Private Members - //------------------------------------------------------------------------- - private: - - E m_error; - }; - -#endif - - namespace detail { - - template - using failure_is_value_convertible = std::integral_constant::value && - !std::is_same::type, in_place_t>::value && - !is_failure::type>::value && - !is_result::type>::value - )>; - - template - using failure_is_explicit_value_convertible = std::integral_constant::value && - !std::is_convertible::value - )>; - - template - using failure_is_implicit_value_convertible = std::integral_constant::value && - std::is_convertible::value - )>; - - template - using failure_is_value_assignable = std::integral_constant::type>::value && - !is_failure::type>::value && - std::is_assignable&,E2>::value - )>; - - } // namespace detail - - //=========================================================================== - // class : failure_type - //=========================================================================== - - ////////////////////////////////////////////////////////////////////////////// - /// \brief A semantic type used for distinguishing failure values in an - /// API that returns result types - /// - /// \tparam E the error type - ////////////////////////////////////////////////////////////////////////////// - template - class failure - { - static_assert( - !is_result::type>::value, - "A (possibly CV-qualified) result 'E' type is ill-formed." - ); - static_assert( - !is_failure::type>::value, - "A (possibly CV-qualified) failure 'E' type is ill-formed." - ); - static_assert( - !std::is_void::type>::value, - "A (possibly CV-qualified) 'void' 'E' type is ill-formed." - ); - static_assert( - !std::is_rvalue_reference::value, - "rvalue references for 'E' type is ill-formed. " - "Only lvalue references are valid." - ); - - //------------------------------------------------------------------------- - // Public Member Types - //------------------------------------------------------------------------- - public: - - using error_type = E; - - //------------------------------------------------------------------------- - // Constructors / Assignment - //------------------------------------------------------------------------- - public: - - /// \brief Constructs a failure via default construction - failure() = default; - - /// \brief Constructs a failure by delegating construction to the - /// underlying constructor - /// - /// \param args the arguments to forward to E's constructor - template ::value>::type> - constexpr failure(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs a failure by delegating construction to the - /// underlying constructor - /// - /// \param ilist the initializer list - /// \param args the arguments to forward to E's constructor - template ,Args...>::value>::type> - constexpr failure(in_place_t, std::initializer_list ilist, Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value); - - /// \{ - /// \brief Constructs a failure from the given error - /// - /// \param error the error to create a failure from - template ::value,int>::type = 0> - constexpr failure(E2&& error) - noexcept(std::is_nothrow_constructible::value); - template ::value,int>::type = 0> - constexpr explicit failure(E2&& error) - noexcept(std::is_nothrow_constructible::value); - /// \} - - /// \brief Constructs this failure by copying the contents of an existing - /// one - /// - /// \param other the other failure to copy - /* implicit */ failure(const failure& other) = default; - - /// \brief Constructs this failure by moving the contents of an existing - /// one - /// - /// \param other the other failure to move - /* implicit */ failure(failure&& other) = default; - - /// \brief Constructs this failure by copy-converting \p other - /// - /// \param other the other failure to copy - template ::value>::type> - constexpr /* implicit */ failure(const failure& other) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs this failure by move-converting \p other - /// - /// \param other the other failure to copy - template ::value>::type> - constexpr /* implicit */ failure(failure&& other) - noexcept(std::is_nothrow_constructible::value); - - //-------------------------------------------------------------------------- - - /// \brief Assigns the value of \p error to this failure through - /// move-assignment - /// - /// \param error the value to assign - /// \return reference to `(*this)` - template ::value>::type> - RESULT_CPP14_CONSTEXPR - auto operator=(E2&& error) - noexcept(std::is_nothrow_assignable::value || std::is_lvalue_reference::value) -> failure&; - - /// \brief Assigns the contents of \p other to this by copy-assignment - /// - /// \param other the other failure to copy - /// \return reference to `(*this)` - auto operator=(const failure& other) -> failure& = default; - - /// \brief Assigns the contents of \p other to this by move-assignment - /// - /// \param other the other failure to move - /// \return reference to `(*this)` - auto operator=(failure&& other) -> failure& = default; - - /// \brief Assigns the contents of \p other to this by copy conversion - /// - /// \param other the other failure to copy-convert - /// \return reference to `(*this)` - template ::value>::type> - RESULT_CPP14_CONSTEXPR - auto operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) -> failure&; - - /// \brief Assigns the contents of \p other to this by move conversion - /// - /// \param other the other failure to move-convert - /// \return reference to `(*this)` - template ::value>::type> - RESULT_CPP14_CONSTEXPR - auto operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) -> failure&; - - //-------------------------------------------------------------------------- - // Observers - //-------------------------------------------------------------------------- - public: - - /// \{ - /// \brief Gets the underlying error - /// - /// \return the underlying error - RESULT_CPP14_CONSTEXPR - auto error() & noexcept - -> typename std::add_lvalue_reference::type; - RESULT_CPP14_CONSTEXPR - auto error() && noexcept - -> typename std::add_rvalue_reference::type; - constexpr auto error() const & noexcept - -> typename std::add_lvalue_reference::type>::type; - constexpr auto error() const && noexcept - -> typename std::add_rvalue_reference::type>::type; - /// \} - - //------------------------------------------------------------------------- - // Private Member Types - //------------------------------------------------------------------------- - private: - - using underlying_type = detail::wrapped_result_type; - - //------------------------------------------------------------------------- - // Private Members - //------------------------------------------------------------------------- - private: - - underlying_type m_failure; - }; - -#if __cplusplus >= 201703L - template - failure(std::reference_wrapper) -> failure; - - template - failure(T&&) -> failure::type>; -#endif - - //=========================================================================== - // non-member functions : class : failure - //=========================================================================== - - //--------------------------------------------------------------------------- - // Comparison - //--------------------------------------------------------------------------- - - template - constexpr auto operator==(const failure& lhs, - const failure& rhs) noexcept -> bool; - template - constexpr auto operator!=(const failure& lhs, - const failure& rhs) noexcept -> bool; - template - constexpr auto operator<(const failure& lhs, - const failure& rhs) noexcept -> bool; - template - constexpr auto operator>(const failure& lhs, - const failure& rhs) noexcept -> bool; - template - constexpr auto operator<=(const failure& lhs, - const failure& rhs) noexcept -> bool; - template - constexpr auto operator>=(const failure& lhs, - const failure& rhs) noexcept -> bool; - - //--------------------------------------------------------------------------- - // Utilities - //--------------------------------------------------------------------------- - - /// \brief Deduces and constructs a failure type from \p e - /// - /// \param e the failure value - /// \return a constructed failure value - template - RESULT_WARN_UNUSED - constexpr auto fail(E&& e) - noexcept(std::is_nothrow_constructible::type,E>::value) - -> failure::type>; - - /// \brief Deduces a failure reference from a reverence_wrapper - /// - /// \param e the failure value - /// \return a constructed failure reference - template - RESULT_WARN_UNUSED - constexpr auto fail(std::reference_wrapper e) - noexcept -> failure; - - /// \brief Constructs a failure type from a series of arguments - /// - /// \tparam E the failure type - /// \param args the arguments to forward to E's constructor - /// \return a constructed failure type - template ::value>::type> - RESULT_WARN_UNUSED - constexpr auto fail(Args&&...args) - noexcept(std::is_nothrow_constructible::value) - -> failure; - - /// \brief Constructs a failure type from an initializer list and series of - /// arguments - /// - /// \tparam E the failure type - /// \param args the arguments to forward to E's constructor - /// \return a constructed failure type - template ,Args...>::value>::type> - RESULT_WARN_UNUSED - constexpr auto fail(std::initializer_list ilist, Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value) - -> failure; - - /// \brief Swaps the contents of two failure values - /// - /// \param lhs the left failure - /// \param rhs the right failure - template - auto swap(failure& lhs, failure& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_swappable::value) -> void; -#else - noexcept(std::is_nothrow_move_constructible::value) -> void; -#endif - - namespace detail { - - //========================================================================= - // class : unit - //========================================================================= - - /// \brief A standalone monostate object (effectively std::monostate). This - /// exists to allow for `void` specializations - struct unit {}; - - //========================================================================= - // non-member functions : class : unit - //========================================================================= - - constexpr auto operator==(unit, unit) noexcept -> bool { return true; } - constexpr auto operator!=(unit, unit) noexcept -> bool { return false; } - constexpr auto operator<(unit, unit) noexcept -> bool { return false; } - constexpr auto operator>(unit, unit) noexcept -> bool { return false; } - constexpr auto operator<=(unit, unit) noexcept -> bool { return true; } - constexpr auto operator>=(unit, unit) noexcept -> bool { return true; } - - //========================================================================= - // class : detail::result_union - //========================================================================= - - /////////////////////////////////////////////////////////////////////////// - /// \brief A basic utility that acts as a union containing the T and E - /// types - /// - /// This is specialized on the case that both T and E are trivial, in which - /// case `result_union` is also trivial - /// - /// \tparam T the value type result to be returned - /// \tparam E the error type returned on failure - /// \tparam IsTrivial Whether or not both T and E are trivial - /////////////////////////////////////////////////////////////////////////// - template ::value && - std::is_trivially_destructible::value> - struct result_union - { - //----------------------------------------------------------------------- - // Public Member Types - //----------------------------------------------------------------------- - - using underlying_value_type = wrapped_result_type; - using underlying_error_type = E; - - //----------------------------------------------------------------------- - // Constructors / Assignment - //----------------------------------------------------------------------- - - /// \brief Constructs an empty object - /// - /// This is for use with conversion constructors, since it allows a - /// temporary unused object to be set - result_union(unit) noexcept; - - /// \brief Constructs the underlying value from the specified \p args - /// - /// \param args the arguments to forward to T's constructor - template - constexpr result_union(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs the underlying error from the specified \p args - /// - /// \param args the arguments to forward to E's constructor - template - constexpr result_union(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - result_union(const result_union&) = default; - result_union(result_union&&) = default; - - //----------------------------------------------------------------------- - - auto operator=(const result_union&) -> result_union& = default; - auto operator=(result_union&&) -> result_union& = default; - - //----------------------------------------------------------------------- - // Modifiers - //----------------------------------------------------------------------- - - /// \brief A no-op for trivial types - auto destroy() const noexcept -> void; - - //----------------------------------------------------------------------- - // Public Members - //----------------------------------------------------------------------- - - union { - underlying_value_type m_value; - underlying_error_type m_error; - unit m_empty; - }; - bool m_has_value; - }; - - //------------------------------------------------------------------------- - - template - struct result_union - { - //----------------------------------------------------------------------- - // Public Member Types - //----------------------------------------------------------------------- - - using underlying_value_type = wrapped_result_type; - using underlying_error_type = E; - - //----------------------------------------------------------------------- - // Constructors / Assignment / Destructor - //----------------------------------------------------------------------- - - /// \brief Constructs an empty object - /// - /// This is for use with conversion constructors, since it allows a - /// temporary unused object to be set - result_union(unit) noexcept; - - /// \brief Constructs the underlying value from the specified \p args - /// - /// \param args the arguments to forward to T's constructor - template - constexpr result_union(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs the underlying error from the specified \p args - /// - /// \param args the arguments to forward to E's constructor - template - constexpr result_union(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - result_union(const result_union&) = default; - result_union(result_union&&) = default; - - //----------------------------------------------------------------------- - - /// \brief Destroys the underlying stored object - ~result_union() - noexcept(std::is_nothrow_destructible::value && - std::is_nothrow_destructible::value); - - //----------------------------------------------------------------------- - - auto operator=(const result_union&) -> result_union& = default; - auto operator=(result_union&&) -> result_union& = default; - - //----------------------------------------------------------------------- - // Modifiers - //----------------------------------------------------------------------- - - /// \brief Destroys the underlying stored object - auto destroy() -> void; - - //----------------------------------------------------------------------- - // Public Members - //----------------------------------------------------------------------- - - union { - underlying_value_type m_value; - underlying_error_type m_error; - unit m_empty; - }; - bool m_has_value; - }; - - //========================================================================= - // class : result_construct_base - //========================================================================= - - /////////////////////////////////////////////////////////////////////////// - /// \brief Base class of assignment to enable construction and assignment - /// - /// This class is used with several pieces of construction to ensure - /// trivial constructibility and assignability: - /// - /// * `result_trivial_copy_ctor_base` - /// * `result_trivial_move_ctor_base` - /// * `result_copy_assign_base` - /// * `result_move_assign_base` - /// - /// \tparam T the value type - /// \tparam E the error type - /////////////////////////////////////////////////////////////////////////// - template - struct result_construct_base - { - //----------------------------------------------------------------------- - // Constructors / Assignment - //----------------------------------------------------------------------- - - /// \brief Constructs an empty object - /// - /// This is for use with conversion constructors, since it allows a - /// temporary unused object to be set - result_construct_base(unit) noexcept; - - /// \brief Constructs the underlying value from the specified \p args - /// - /// \param args the arguments to forward to T's constructor - template - constexpr result_construct_base(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs the underlying error from the specified \p args - /// - /// \param args the arguments to forward to E's constructor - template - constexpr result_construct_base(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value); - - result_construct_base(const result_construct_base&) = default; - result_construct_base(result_construct_base&&) = default; - - auto operator=(const result_construct_base&) -> result_construct_base& = default; - auto operator=(result_construct_base&&) -> result_construct_base& = default; - - //----------------------------------------------------------------------- - // Construction / Assignment - //----------------------------------------------------------------------- - - /// \brief Constructs the value type from \p args - /// - /// \note This is an implementation detail only meant to be used during - /// construction - /// - /// \pre there is no contained value or error at the time of construction - /// - /// \param args the arguments to forward to T's constructor - template - auto construct_value(Args&&...args) - noexcept(std::is_nothrow_constructible::value) -> void; - - /// \brief Constructs the error type from \p args - /// - /// \note This is an implementation detail only meant to be used during - /// construction - /// - /// \pre there is no contained value or error at the time of construction - /// - /// \param args the arguments to forward to E's constructor - template - auto construct_error(Args&&...args) - noexcept(std::is_nothrow_constructible::value) -> void; - - /// \brief Constructs the underlying error from the \p other result - /// - /// If \p other contains a value, then the T type will be - /// default-constructed. - /// - /// \note This is an implementation detail only meant to be used during - /// construction of `result` types - /// - /// \pre there is no contained value or error at the time of construction - /// - /// \param other the other result to construct - template - auto construct_error_from_result(Result&& other) -> void; - - /// \brief Constructs the underlying type from a result object - /// - /// \note This is an implementation detail only meant to be used during - /// construction - /// - /// \pre there is no contained value or error at the time of construction - /// - /// \param other the other result to construct - template - auto construct_from_result(Result&& other) -> void; - - //----------------------------------------------------------------------- - - template - auto assign_value(Value&& value) - noexcept(std::is_nothrow_assignable::value) -> void; - - template - auto assign_error(Error&& error) - noexcept(std::is_nothrow_assignable::value) -> void; - - template - auto assign_from_result(Result&& other) -> void; - - //----------------------------------------------------------------------- - - template - auto construct_value_from_result_impl(std::true_type, ReferenceWrapper&& reference) - noexcept -> void; - - template - auto construct_value_from_result_impl(std::false_type, Value&& value) - noexcept(std::is_nothrow_constructible::value) -> void; - - template - auto assign_value_from_result_impl(std::true_type, Result&& other) -> void; - - template - auto assign_value_from_result_impl(std::false_type, Result&& other) -> void; - - //----------------------------------------------------------------------- - // Public Members - //----------------------------------------------------------------------- - - using storage_type = result_union; - - storage_type storage; - }; - - //========================================================================= - // class : result_trivial_copy_ctor_base - //========================================================================= - - template - struct result_trivial_copy_ctor_base_impl : result_construct_base - { - using base_type = result_construct_base; - using base_type::base_type; - - result_trivial_copy_ctor_base_impl(const result_trivial_copy_ctor_base_impl& other) - noexcept(std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_constructible::value); - result_trivial_copy_ctor_base_impl(result_trivial_copy_ctor_base_impl&& other) = default; - - auto operator=(const result_trivial_copy_ctor_base_impl& other) -> result_trivial_copy_ctor_base_impl& = default; - auto operator=(result_trivial_copy_ctor_base_impl&& other) -> result_trivial_copy_ctor_base_impl& = default; - }; - - template - using conditionally_nest_type = typename std::conditional< - Condition, - typename Base::base_type, - Base - >::type; - - template - using result_trivial_copy_ctor_base = conditionally_nest_type< - std::is_trivially_copy_constructible::value && - std::is_trivially_copy_constructible::value, - result_trivial_copy_ctor_base_impl - >; - - //========================================================================= - // class : result_trivial_move_ctor_base - //========================================================================= - - template - struct result_trivial_move_ctor_base_impl : result_trivial_copy_ctor_base - { - using base_type = result_trivial_copy_ctor_base; - using base_type::base_type; - - result_trivial_move_ctor_base_impl(const result_trivial_move_ctor_base_impl& other) = default; - result_trivial_move_ctor_base_impl(result_trivial_move_ctor_base_impl&& other) - noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value); - - auto operator=(const result_trivial_move_ctor_base_impl& other) -> result_trivial_move_ctor_base_impl& = default; - auto operator=(result_trivial_move_ctor_base_impl&& other) -> result_trivial_move_ctor_base_impl& = default; - }; - - template - using result_trivial_move_ctor_base = conditionally_nest_type< - std::is_trivially_move_constructible::value && - std::is_trivially_move_constructible::value, - result_trivial_move_ctor_base_impl - >; - - //========================================================================= - // class : result_trivial_copy_assign_base - //========================================================================= - - template - struct result_trivial_copy_assign_base_impl - : result_trivial_move_ctor_base - { - using base_type = result_trivial_move_ctor_base; - using base_type::base_type; - - result_trivial_copy_assign_base_impl(const result_trivial_copy_assign_base_impl& other) = default; - result_trivial_copy_assign_base_impl(result_trivial_copy_assign_base_impl&& other) = default; - - auto operator=(const result_trivial_copy_assign_base_impl& other) - noexcept(std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_assignable::value && - std::is_nothrow_copy_assignable::value) - -> result_trivial_copy_assign_base_impl&; - auto operator=(result_trivial_copy_assign_base_impl&& other) - -> result_trivial_copy_assign_base_impl& = default; - }; - - template - using result_trivial_copy_assign_base = conditionally_nest_type< - std::is_trivially_copy_constructible::value && - std::is_trivially_copy_constructible::value && - std::is_trivially_copy_assignable::value && - std::is_trivially_copy_assignable::value && - std::is_trivially_destructible::value && - std::is_trivially_destructible::value, - result_trivial_copy_assign_base_impl - >; - - //========================================================================= - // class : result_trivial_move_assign_base - //========================================================================= - - template - struct result_trivial_move_assign_base_impl - : result_trivial_copy_assign_base - { - using base_type = result_trivial_copy_assign_base; - using base_type::base_type; - - result_trivial_move_assign_base_impl(const result_trivial_move_assign_base_impl& other) = default; - result_trivial_move_assign_base_impl(result_trivial_move_assign_base_impl&& other) = default; - - auto operator=(const result_trivial_move_assign_base_impl& other) - -> result_trivial_move_assign_base_impl& = default; - auto operator=(result_trivial_move_assign_base_impl&& other) - noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_assignable::value) - -> result_trivial_move_assign_base_impl&; - }; - - template - using result_trivial_move_assign_base = conditionally_nest_type< - std::is_trivially_move_constructible::value && - std::is_trivially_move_constructible::value && - std::is_trivially_move_assignable::value && - std::is_trivially_move_assignable::value && - std::is_trivially_destructible::value && - std::is_trivially_destructible::value, - result_trivial_move_assign_base_impl - >; - - //========================================================================= - // class : disable_copy_ctor - //========================================================================= - - template - struct disable_copy_ctor : result_trivial_move_assign_base - { - using base_type = result_trivial_move_assign_base; - using base_type::base_type; - - disable_copy_ctor(const disable_copy_ctor& other) = delete; - disable_copy_ctor(disable_copy_ctor&& other) = default; - - auto operator=(const disable_copy_ctor& other) - -> disable_copy_ctor& = default; - auto operator=(disable_copy_ctor&& other) - -> disable_copy_ctor& = default; - }; - - template - using result_copy_ctor_base = conditionally_nest_type< - std::is_copy_constructible::value && - std::is_copy_constructible::value, - disable_copy_ctor - >; - - //========================================================================= - // class : disable_move_ctor - //========================================================================= - - template - struct disable_move_ctor : result_copy_ctor_base - { - using base_type = result_copy_ctor_base; - using base_type::base_type; - - disable_move_ctor(const disable_move_ctor& other) = default; - disable_move_ctor(disable_move_ctor&& other) = delete; - - auto operator=(const disable_move_ctor& other) - -> disable_move_ctor& = default; - auto operator=(disable_move_ctor&& other) - -> disable_move_ctor& = default; - }; - - template - using result_move_ctor_base = conditionally_nest_type< - std::is_move_constructible::value && - std::is_move_constructible::value, - disable_move_ctor - >; - - //========================================================================= - // class : disable_move_assignment - //========================================================================= - - template - struct disable_move_assignment - : result_move_ctor_base - { - using base_type = result_move_ctor_base; - using base_type::base_type; - - disable_move_assignment(const disable_move_assignment& other) = default; - disable_move_assignment(disable_move_assignment&& other) = default; - - auto operator=(const disable_move_assignment& other) - -> disable_move_assignment& = delete; - auto operator=(disable_move_assignment&& other) - -> disable_move_assignment& = default; - }; - - template - using result_copy_assign_base = conditionally_nest_type< - std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_constructible::value && - std::is_copy_assignable>::value && - std::is_copy_assignable::value, - disable_move_assignment - >; - - //========================================================================= - // class : disable_copy_assignment - //========================================================================= - - template - struct disable_copy_assignment - : result_copy_assign_base - { - using base_type = result_copy_assign_base; - using base_type::base_type; - - disable_copy_assignment(const disable_copy_assignment& other) = default; - disable_copy_assignment(disable_copy_assignment&& other) = default; - - auto operator=(const disable_copy_assignment& other) - -> disable_copy_assignment& = default; - auto operator=(disable_copy_assignment&& other) - -> disable_copy_assignment& = delete; - }; - - template - using result_move_assign_base = conditionally_nest_type< - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value && - std::is_move_assignable>::value && - std::is_move_assignable::value, - disable_copy_assignment - >; - - //========================================================================= - // alias : result_storage - //========================================================================= - - template - using result_storage = result_move_assign_base; - - //========================================================================= - // traits : result - //========================================================================= - - template - using result_is_convertible = std::integral_constant - std::is_constructible&>:: value || - std::is_constructible&>:: value || - std::is_constructible&&>:: value || - std::is_constructible&&>:: value || - - // E1 constructible from result - std::is_constructible&>:: value || - std::is_constructible&>:: value || - std::is_constructible&&>:: value || - std::is_constructible&&>:: value || - - // result convertible to T1 - std::is_convertible&, T1>:: value || - std::is_convertible&, T1>:: value || - std::is_convertible&&, T1>::value || - std::is_convertible&&, T1>::value || - - // result convertible to E2 - std::is_convertible&, E1>:: value || - std::is_convertible&, E1>:: value || - std::is_convertible&&, E1>::value || - std::is_convertible&&, E1>::value - )>; - - //------------------------------------------------------------------------- - - template - using result_is_copy_convertible = std::integral_constant::value && - std::is_constructible::value && - std::is_constructible::value - )>; - - template - using result_is_implicit_copy_convertible = std::integral_constant::value && - std::is_convertible::value && - std::is_convertible::value - )>; - - template - using result_is_explicit_copy_convertible = std::integral_constant::value && - (!std::is_convertible::value || - !std::is_convertible::value) - )>; - - //------------------------------------------------------------------------- - - template - using result_is_move_convertible = std::integral_constant::value && - std::is_constructible::value && - std::is_constructible::value - )>; - - template - using result_is_implicit_move_convertible = std::integral_constant::value && - std::is_convertible::value && - std::is_convertible::value - )>; - - template - using result_is_explicit_move_convertible = std::integral_constant::value && - (!std::is_convertible::value || - !std::is_convertible::value) - )>; - - //------------------------------------------------------------------------- - - template - using result_is_value_convertible = std::integral_constant::value && - !std::is_same::type, in_place_t>::value && - !std::is_same::type, in_place_error_t>::value && - !is_result::type>::value - )>; - - template - using result_is_explicit_value_convertible = std::integral_constant::value && - !std::is_convertible::value - )>; - - template - using result_is_implicit_value_convertible = std::integral_constant::value && - std::is_convertible::value - )>; - - //------------------------------------------------------------------------- - - template - using result_is_convert_assignable = std::integral_constant::value && - - std::is_assignable&>::value && - std::is_assignable&>::value && - std::is_assignable&&>::value && - std::is_assignable&&>::value && - - std::is_assignable&>::value && - std::is_assignable&>::value && - std::is_assignable&&>::value && - std::is_assignable&&>::value - )>; - - template - using result_is_copy_convert_assignable = std::integral_constant::value && - - std::is_nothrow_constructible::value && - std::is_assignable&, const T2&>::value && - std::is_nothrow_constructible::value && - std::is_assignable::value - )>; - - template - using result_is_move_convert_assignable = std::integral_constant::value && - - std::is_nothrow_constructible::value && - std::is_assignable::value && - std::is_nothrow_constructible::value && - std::is_assignable::value - )>; - - //------------------------------------------------------------------------- - - template - using result_is_value_assignable = std::integral_constant::type>::value && - !is_failure::type>::value && - std::is_nothrow_constructible::value && - std::is_assignable&,U>::value && - ( - !std::is_same::type,typename std::decay::type>::value || - !std::is_scalar::value - ) - )>; - - template - using result_is_failure_assignable = std::integral_constant::value && - std::is_assignable::value - )>; - - // Friending 'extract_error" below was causing some compilers to incorrectly - // identify `exp.m_storage.m_error` as being an access violation despite the - // friendship. Using a type name instead seems to be ubiquitous across - // compilers - struct result_error_extractor - { - template - static constexpr auto get(const result& exp) noexcept -> const E&; - template - static constexpr auto get(result& exp) noexcept -> E&; - }; - - template - constexpr auto extract_error(const result& exp) noexcept -> const E&; - - template - [[noreturn]] - auto throw_bad_result_access(E&& error) -> void; - - template - [[noreturn]] - auto throw_bad_result_access_message(String&& message, E&& error) -> void; - - } // namespace detail - - ///////////////////////////////////////////////////////////////////////////// - /// \brief The class template `result` manages result results from APIs, - /// while encoding possible failure conditions. - /// - /// A common use-case for result is the return value of a function that - /// may fail. As opposed to other approaches, such as `std::pair` - /// or `std::optional`, `result` more accurately conveys the intent of the - /// user along with the failure condition to the caller. This effectively - /// produces an orthogonal error handling mechanism that allows for exception - /// safety while also allowing discrete testability of the return type. - /// - /// `result` types may contain a `T` value, which signifies that an - /// operation succeeded in producing the result value of type `T`. If an - /// `result` does not contain a `T` value, it will always contain an `E` - /// error condition instead. - /// - /// An `result` can always be queried for a possible error case by - /// calling the `error()` function, even if it contains a value. - /// In the case that a `result` contains a value object, this will - /// simply return an `E` object constructed through default aggregate - /// construction, as if through the expression `E{}`, which is assumed to be - /// a "valid" (no-error) state for an `E` type. - /// For example: - /// - /// * `std::error_code{}` produces a default-construct error-code, which is - /// the "no error" state, - /// * integral (or enum) error codes produce a `0` value (no error), thanks to - /// zero-initialization, - /// * `std::exception_ptr{}` produces a null-pointer, - /// * `std::string{}` produces an empty string `""`, - /// * etc. - /// - /// When a `result` contains either a value or error, the storage for - /// that object is guaranteed to be allocated as part of the result - /// object's footprint, i.e. no dynamic memory allocation ever takes place. - /// Thus, a result object models an object, not a pointer, even though the - /// `operator*()` and `operator->()` are defined. - /// - /// When an object of type `result` is contextually converted to - /// `bool`, the conversion returns `true` if the object contains a value and - /// `false` if it contains an error. - /// - /// `result` objects do not have a "valueless" state like `variant`s do. - /// Once a `result` has been constructed with a value or error, the - /// active underlying type can only be changed through assignment which may - /// is only enabled if construction is guaranteed to be *non-throwing*. This - /// ensures that a valueless state cannot occur naturally. - /// - /// Example Use: - /// \code - /// auto to_string(int x) -> result - /// { - /// try { - /// return std::stoi(x); - /// } catch (const std::invalid_argument&) { - /// return fail(std::errc::invalid_argument); - /// } catch (const std::std::out_of_range&) { - /// return fail(std::errc::result_out_of_range); - /// } - /// } - /// \endcode - /// - /// \note If using C++17 or above, `fail` can be replaced with - /// `failure{...}` thanks to CTAD. - /// - /// \tparam T the underlying value type - /// \tparam E the underlying error type - /////////////////////////////////////////////////////////////////////////// - template - class RESULT_NODISCARD result - { - // Type requirements - - static_assert( - !std::is_abstract::value, - "It is ill-formed for T to be abstract type" - ); - static_assert( - !std::is_same::type, in_place_t>::value, - "It is ill-formed for T to be a (possibly CV-qualified) in_place_t type" - ); - static_assert( - !is_result::type>::value, - "It is ill-formed for T to be a (possibly CV-qualified) 'result' type" - ); - static_assert( - !is_failure::type>::value, - "It is ill-formed for T to be a (possibly CV-qualified) 'failure' type" - ); - static_assert( - !std::is_rvalue_reference::value, - "It is ill-formed for T to be an rvalue 'result type. " - "Only lvalue references are valid." - ); - - static_assert( - !std::is_abstract::value, - "It is ill-formed for E to be abstract type" - ); - static_assert( - !std::is_void::type>::value, - "It is ill-formed for E to be (possibly CV-qualified) void type" - ); - static_assert( - !is_result::type>::value, - "It is ill-formed for E to be a (possibly CV-qualified) 'result' type" - ); - static_assert( - !is_failure::type>::value, - "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type" - ); - static_assert( - !std::is_same::type, in_place_t>::value, - "It is ill-formed for E to be a (possibly CV-qualified) in_place_t type" - ); - static_assert( - !std::is_reference::value, - "It is ill-formed for E to be a reference type. " - "Only T types may be lvalue references" - ); - - // Friendship - - friend detail::result_error_extractor; - - template - friend class result; - - //------------------------------------------------------------------------- - // Public Member Types - //------------------------------------------------------------------------- - public: - - using value_type = T; ///< The value type of this result - using error_type = E; ///< The error type of this result - using failure_type = failure; ///< The failure type - - template - using rebind = result; ///< Rebinds the result type - - //------------------------------------------------------------------------- - // Constructor / Destructor / Assignment - //------------------------------------------------------------------------- - public: - - /// \brief Default-constructs a result with the underlying value type - /// active - /// - /// This constructor is only enabled if `T` is default-constructible - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// assert(cpp::result{} == std::string{}); - /// ``` - template ::value>::type> - constexpr result() - noexcept(std::is_nothrow_constructible::value); - - /// \brief Copy constructs this result - /// - /// If \p other contains a value, initializes the contained value as if - /// direct-initializing (but not direct-list-initializing) an object of - /// type `T` with the expression *other. - /// - /// If other contains an error, constructs an object that contains a copy - /// of that error. - /// - /// \note This constructor is defined as deleted if - /// `std::is_copy_constructible::value` or - /// `std::is_copy_constructible::value` is `false` - /// - /// \note This constructor is defined as trivial if both - /// `std::is_trivially_copy_constructible::value` and - /// `std::is_trivially_copy_constructible::value` are `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// const auto r = cpp::result{42}; - /// const auto s = r; - /// - /// assert(r == s); - /// ``` - /// - /// \param other the result to copy - constexpr result(const result& other) = default; - - /// \brief Move constructs a result - /// - /// If other contains a value, initializes the contained value as if - /// direct-initializing (but not direct-list-initializing) an object - /// of type T with the expression `std::move(*other)` and does not make - /// other empty: a moved-from result still contains a value, but the - /// value itself is moved from. - /// - /// If other contains an error, move-constructs this result from that - /// error. - /// - /// \note This constructor is defined as deleted if - /// `std::is_move_constructible::value` or - /// `std::is_move_constructible::value` is `false` - /// - /// \note This constructor is defined as trivial if both - /// `std::is_trivially_move_constructible::value` and - /// `std::is_trivially_move_constructible::value` are `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{"hello world"}; - /// auto s = std::move(r); - /// - /// assert(s == "hello world"); - /// ``` - /// - /// \param other the result to move - constexpr result(result&& other) = default; - - /// \{ - /// \brief Converting copy constructor - /// - /// If \p other contains a value, constructs a result object - /// that contains a value, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type `T` with the - /// expression `*other`. - /// - /// If \p other contains an error, constructs a result object that - /// contains an error, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type `E`. - /// - /// \note This constructor does not participate in overload resolution - /// unless the following conditions are met: - /// - `std::is_constructible_v` is `true` - /// - T is not constructible or convertible from any expression - /// of type (possibly const) `result` - /// - E is not constructible or convertible from any expression - /// of type (possible const) `result` - /// - /// \note This constructor is explicit if and only if - /// `std::is_convertible_v` or - /// `std::is_convertible_v` is `false` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// const auto r = cpp::result{42}; - /// const auto s = cpp::result{r}; - /// - /// assert(r == s); - /// ``` - /// - /// \param other the other type to convert - template ::value,int>::type = 0> - result(const result& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); - template ::value,int>::type = 0> - explicit result(const result& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); - /// \} - - /// \{ - /// \brief Converting move constructor - /// - /// If \p other contains a value, constructs a result object - /// that contains a value, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type T with the - /// expression `std::move(*other)`. - /// - /// If \p other contains an error, constructs a result object that - /// contains an error, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type E&&. - /// - /// \note This constructor does not participate in overload resolution - /// unless the following conditions are met: - /// - `std::is_constructible_v` is `true` - /// - T is not constructible or convertible from any expression - /// of type (possibly const) `result` - /// - E is not constructible or convertible from any expression - /// of type (possible const) `result` - /// - /// \note This constructor is explicit if and only if - /// `std::is_convertible_v` or - /// `std::is_convertible_v` is `false` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result,int>{ - /// std::make_unique() - /// }; - /// const auto s = cpp::result,long>{ - /// std::move(r) - /// }; - /// ``` - /// - /// \param other the other type to convert - template ::value,int>::type = 0> - result(result&& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); - template ::value,int>::type = 0> - explicit result(result&& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value); - /// \} - - //------------------------------------------------------------------------- - - /// \brief Constructs a result object that contains a value - /// - /// The value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `T` from the arguments - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place, "Hello world" - /// }; - /// ``` - /// - /// \param args the arguments to pass to T's constructor - template ::value>::type> - constexpr explicit result(in_place_t, Args&&... args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs a result object that contains a value - /// - /// The value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `T` from the arguments - /// `std::forward>(ilist)`, - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place, {'H','e','l','l','o'} - /// }; - /// ``` - /// - /// \param ilist An initializer list of entries to forward - /// \param args the arguments to pass to T's constructor - template &, Args...>::value>::type> - constexpr explicit result(in_place_t, - std::initializer_list ilist, - Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value); - - //------------------------------------------------------------------------- - - /// \brief Constructs a result object that contains an error - /// - /// the value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `E` from the arguments - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place_error, "Hello world" - /// }; - /// ``` - /// - /// \param args the arguments to pass to E's constructor - template ::value>::type> - constexpr explicit result(in_place_error_t, Args&&... args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs a result object that contains an error - /// - /// The value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `E` from the arguments - /// `std::forward>(ilist)`, - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place_error, {'H','e','l','l','o'} - /// }; - /// ``` - /// - /// \param ilist An initializer list of entries to forward - /// \param args the arguments to pass to Es constructor - template &, Args...>::value>::type> - constexpr explicit result(in_place_error_t, - std::initializer_list ilist, - Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value); - - //------------------------------------------------------------------------- - - /// \{ - /// \brief Constructs the underlying error of this result - /// - /// \note This constructor only participates in overload resolution if - /// `E` is constructible from \p e - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// cpp::result r = cpp::fail(42); - /// - /// auto get_error_result() -> cpp::result { - /// return cpp::fail("hello world!"); - /// } - /// ``` - /// - /// \param e the failure error - template ::value>::type> - constexpr /* implicit */ result(const failure& e) - noexcept(std::is_nothrow_constructible::value); - template ::value>::type> - constexpr /* implicit */ result(failure&& e) - noexcept(std::is_nothrow_constructible::value); - /// \} - - /// \{ - /// \brief Constructs a result object that contains a value - /// - /// The value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type T with the expression - /// value. - /// - /// \note This constructor is constexpr if the constructor of T - /// selected by direct-initialization is constexpr - /// - /// \note This constructor does not participate in overload - /// resolution unless `std::is_constructible_v` is true - /// and `decay_t` is neither `in_place_t`, `in_place_error_t`, - /// nor a `result` type. - /// - /// \note This constructor is explicit if and only if - /// `std::is_convertible_v` is `false` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// cpp::result r = 42; - /// - /// auto get_value() -> cpp::result { - /// return "hello world!"; // implicit conversion - /// } - /// ``` - /// - /// \param value the value to copy - template ::value,int>::type = 0> - constexpr explicit result(U&& value) - noexcept(std::is_nothrow_constructible::value); - template ::value,int>::type = 0> - constexpr /* implicit */ result(U&& value) - noexcept(std::is_nothrow_constructible::value); - /// \} - - //------------------------------------------------------------------------- - - /// \brief Copy assigns the result stored in \p other - /// - /// \note This assignment operator only participates in overload resolution - /// if the following conditions are met: - /// - `std::is_nothrow_copy_constructible_v` is `true`, and - /// - `std::is_nothrow_copy_constructible_v` is `true` - /// this restriction guarantees that no ' - /// - /// \note This assignment operator is defined as trivial if the following - /// conditions are all `true`: - /// - `std::is_trivially_copy_constructible::value` - /// - `std::is_trivially_copy_constructible::value` - /// - `std::is_trivially_copy_assignable::value` - /// - `std::is_trivially_copy_assignable::value` - /// - `std::is_trivially_destructible::value` - /// - `std::is_trivially_destructible::value` - /// - /// \param other the other result to copy - auto operator=(const result& other) -> result& = default; - - /// \brief Move assigns the result stored in \p other - /// - /// \note This assignment operator only participates in overload resolution - /// if the following conditions are met: - /// - `std::is_nothrow_copy_constructible_v` is `true`, and - /// - `std::is_nothrow_copy_constructible_v` is `true` - /// this restriction guarantees that no 'valueless_by_exception` state - /// may occur. - /// - /// \note This assignment operator is defined as trivial if the following - /// conditions are all `true`: - /// - `std::is_trivially_move_constructible::value` - /// - `std::is_trivially_move_constructible::value` - /// - `std::is_trivially_move_assignable::value` - /// - `std::is_trivially_move_assignable::value` - /// - `std::is_trivially_destructible::value` - /// - `std::is_trivially_destructible::value` - /// - /// \param other the other result to copy - auto operator=(result&& other) -> result& = default; - - /// \brief Copy-converts the state of \p other - /// - /// If both `*this` and \p other contain either values or errors, the - /// underlying value is constructed as if through assignment. - /// - /// Otherwise if `*this` contains a value, but \p other contains an error, - /// then the contained value is destroyed by calling its destructor. `*this` - /// will no longer contain a value after the call, and will now contain `E` - /// constructed as if direct-initializing (but not direct-list-initializing) - /// an object with an argument of `const E2&`. - /// - /// If \p other contains a value and `*this` contains an error, then the - /// contained error is destroyed by calling its destructor. `*this` now - /// contains a value constructed as if direct-initializing (but not - /// direct-list-initializing) an object with an argument of `const T2&`. - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v`, - /// `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v` are all true. - /// - T is not constructible, convertible, or assignable from any - /// expression of type (possibly const) `result` - /// - /// \param other the other result object to convert - /// \return reference to `(*this)` - template ::value>::type> - auto operator=(const result& other) - noexcept(std::is_nothrow_assignable::value && - std::is_nothrow_assignable::value) -> result&; - - /// \brief Move-converts the state of \p other - /// - /// If both `*this` and \p other contain either values or errors, the - /// underlying value is constructed as if through move-assignment. - /// - /// Otherwise if `*this` contains a value, but \p other contains an error, - /// then the contained value is destroyed by calling its destructor. `*this` - /// will no longer contain a value after the call, and will now contain `E` - /// constructed as if direct-initializing (but not direct-list-initializing) - /// an object with an argument of `E2&&`. - /// - /// If \p other contains a value and `*this` contains an error, then the - /// contained error is destroyed by calling its destructor. `*this` now - /// contains a value constructed as if direct-initializing (but not - /// direct-list-initializing) an object with an argument of `T2&&`. - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v`, - /// `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v` are all true. - /// - T is not constructible, convertible, or assignable from any - /// expression of type (possibly const) `result` - /// - /// \param other the other result object to convert - /// \return reference to `(*this)` - template ::value>::type> - auto operator=(result&& other) - noexcept(std::is_nothrow_assignable::value && - std::is_nothrow_assignable::value) -> result&; - - /// \brief Perfect-forwarded assignment - /// - /// Depending on whether `*this` contains a value before the call, the - /// contained value is either direct-initialized from std::forward(value) - /// or assigned from std::forward(value). - /// - /// \note The function does not participate in overload resolution unless - /// - `std::decay_t` is not a result type, - /// - `std::decay_t` is not a failure type - /// - `std::is_nothrow_constructible_v` is `true` - /// - `std::is_assignable_v` is `true` - /// - and at least one of the following is `true`: - /// - `T` is not a scalar type; - /// - `std::decay_t` is not `T`. - /// - /// \param value to assign to the contained value - /// \return reference to `(*this)` - template ::value>::type> - auto operator=(U&& value) - noexcept(std::is_nothrow_assignable::value) -> result&; - - /// \{ - /// \brief Perfect-forwarded assignment - /// - /// Depending on whether `*this` contains an error before the call, the - /// contained error is either direct-initialized via forwarding the error, - /// or assigned from forwarding the error - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v` is `true`, and - /// - `std::is_assignable_v` is `true` - /// - /// \param other the failure value to assign to this - /// \return reference to `(*this)` - template ::value>::type> - auto operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - template ::value>::type> - auto operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - /// \} - - //------------------------------------------------------------------------- - // Observers - //------------------------------------------------------------------------- - public: - - /// \{ - /// \brief Retrieves a pointer to the contained value - /// - /// This operator exists to give `result` an `optional`-like API for cases - /// where it's known that the `result` already contains a value. - /// - /// Care must be taken to ensure that this is only used in safe contexts - /// where a `T` value is active. - /// - /// \note The behavior is undefined if `*this` does not contain a value. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// make_widget() - /// }; - /// - /// r->do_something(); - /// ``` - /// - /// \return a pointer to the contained value - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto operator->() - noexcept -> typename std::remove_reference::type*; - RESULT_WARN_UNUSED - constexpr auto operator->() - const noexcept -> typename std::remove_reference::type>::type*; - /// \} - - /// \{ - /// \brief Retrieves a reference to the contained value - /// - /// This operator exists to give `result` an `optional`-like API for cases - /// where it's known that the `result` already contains a value. - /// - /// Care must be taken to ensure that this is only used in safe contexts - /// where a `T` value is active. - /// - /// \note The behaviour is undefined if `*this` does not contain a value - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// make_widget() - /// }; - /// - /// (*r).do_something(); - /// - /// consume(*r); - /// ``` - /// - /// \return a reference to the contained value - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto operator*() - & noexcept -> typename std::add_lvalue_reference::type; - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto operator*() - && noexcept -> typename std::add_rvalue_reference::type; - RESULT_WARN_UNUSED - constexpr auto operator*() - const& noexcept -> typename std::add_lvalue_reference::type>::type; - RESULT_WARN_UNUSED - constexpr auto operator*() - const&& noexcept -> typename std::add_rvalue_reference::type>::type; - /// \} - - //------------------------------------------------------------------------- - - /// \brief Contextually convertible to `true` if `*this` contains a value - /// - /// This function exists to allow for simple, terse checks for containing - /// a value. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto get_result() -> cpp::result; - /// auto r = get_result(); - /// if (r) { ... } - /// - /// assert(static_cast(cpp::result{42})); - /// - /// assert(!static_cast(cpp::result{cpp::fail(42)})); - /// ``` - /// - /// \return `true` if `*this` contains a value, `false` if `*this` - /// does not contain a value - RESULT_WARN_UNUSED - constexpr explicit operator bool() const noexcept; - - /// \brief Returns `true` if `*this` contains a value - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto get_result() -> cpp::result; - /// auto r = get_result(); - /// if (r.has_value()) { ... } - /// - /// assert(cpp::result{42}.has_value()); - /// - /// assert(!cpp::result{cpp::fail(42)}.has_value()); - /// ``` - /// - /// \return `true` if `*this` contains a value, `false` if `*this` - /// contains an error - RESULT_WARN_UNUSED - constexpr auto has_value() const noexcept -> bool; - - /// \brief Returns `true` if `*this` contains an error - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto get_result() -> cpp::result; - /// - /// auto r = get_result(); - /// if (r.has_error()) { ... } - /// - /// assert(!cpp::result{42}.has_error()); - /// - /// assert(cpp::result{cpp::fail(42)}.has_error()); - /// ``` - /// - /// \return `true` if `*this` contains an error, `false` if `*this` - /// contains a value - RESULT_WARN_UNUSED - constexpr auto has_error() const noexcept -> bool; - - //------------------------------------------------------------------------- - - /// \{ - /// \brief Returns a reference to the contained value - /// - /// This function provides checked (throwing) access to the underlying - /// value. The constness and refness of this result is propagated to the - /// underlying reference. - /// - /// If this contains an error, an exception is thrown containing the - /// underlying error. The error is consumed propagating the same constness - /// and refness of this result. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// assert(cpp::result{42}.value() == 42); - /// - /// auto r = cpp::result,int>{ - /// std::make_unique(42) - /// }; - /// auto s = std::move(r).value(); - /// - /// try { - /// auto r = cpp::result{ cpp::fail(42) }; - /// auto v = r.value(); - /// } catch (const cpp::bad_result_access& e) { - /// assert(e.error() == 42); - /// } - /// ``` - /// - /// \throws bad_result_access if `*this` does not contain a value. - /// - /// \return the value of `*this` - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto value() - & -> typename std::add_lvalue_reference::type; - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto value() - && -> typename std::add_rvalue_reference::type; - RESULT_WARN_UNUSED - constexpr auto value() - const & -> typename std::add_lvalue_reference::type>::type; - RESULT_WARN_UNUSED - constexpr auto value() - const && -> typename std::add_rvalue_reference::type>::type; - /// \} - - /// \{ - /// \brief Returns the contained error, if one exists, or a - /// default-constructed error value - /// - /// The `error()` function will not throw any exceptions if `E` does not - /// throw any exceptions for the copy or move construction. - /// - /// This is to limit the possible scope for exceptions, and to allow the - /// error type to be treated as a "status"-like type, where the - /// default-constructed case is considered the "good" state. - /// - /// If this function is invoked on an rvalue of a result, the error is - /// returned via move-construction - /// - /// ### Requires - /// - /// * `std::is_default_constructible::value` is `true` - /// * `std::is_copy_constructible::value` or - /// `std::is_move_constructible::value` is `true` - /// * `E{}` represents the "good" (non-error) state - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ 42 }; - /// assert(r.error() == std::error_code{}); - /// - /// auto r = cpp::result{ - /// cpp::fail(std::io_errc::stream) - /// }; - /// - /// assert(r.error() == std::io_errc::stream); - /// ``` - /// - /// \return the error or a default-constructed error value - RESULT_WARN_UNUSED - constexpr auto error() const & - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E; - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto error() && - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_move_constructible::value) -> E; - /// } - - /// \{ - /// \brief Asserts an expectation that this result contains an error, - /// throwing a bad_result_access on failure - /// - /// If this function is invoked from an rvalue of `result`, then this will - /// consume the underlying error first, if there is one. - /// - /// \note This function exists as a means to allow for results to be marked - /// `used` without requiring directly inspecting the underlying value. - /// This is, in effect, equivalent to `assert(res.has_value())`, - /// however it uses exceptions to ensure the stack can be unwound, and - /// exceptions invoked. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto start_service() -> cpp::result; - /// - /// start_service().expect("Service failed to start!"); - /// ``` - /// - /// \param message the message to provide to this expectation - /// - /// \return the value of `*this` - template ::value && - std::is_copy_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) & -> typename std::add_lvalue_reference::type; - template ::value && - std::is_move_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> typename std::add_rvalue_reference::type; - template ::value && - std::is_copy_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) const & -> typename std::add_lvalue_reference::type>::type; - template ::value && - std::is_copy_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) const && -> typename std::add_rvalue_reference::type>::type; - /// \} - - //------------------------------------------------------------------------- - // Monadic Functionalities - //------------------------------------------------------------------------- - public: - - /// \{ - /// \brief Returns the contained value if `*this` has a value, - /// otherwise returns \p default_value. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{42}; - /// assert(r.value_or(0) == 42); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.value_or(0) == 0); - /// ``` - /// - /// \param default_value the value to use in case `*this` contains an error - /// \return the contained value or \p default_value - template - RESULT_WARN_UNUSED - constexpr auto value_or(U&& default_value) - const & -> typename std::remove_reference::type; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto value_or(U&& default_value) - && -> typename std::remove_reference::type; - /// \} - - /// \{ - /// \brief Returns the contained error if `*this` has an error, - /// otherwise returns \p default_error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{42}; - /// assert(r.error_or(0) == cpp::fail(0)); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.error_or(0) == cpp::fail(42)); - /// ``` - /// - /// \param default_error the error to use in case `*this` is empty - /// \return the contained value or \p default_error - template - RESULT_WARN_UNUSED - constexpr auto error_or(U&& default_error) const & -> error_type; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type; - /// \} - - //------------------------------------------------------------------------- - - /// \brief Returns a result containing \p value if this result contains - /// a value, otherwise returns a result containing the current - /// error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{42}; - /// assert(r.and_then(100) == 100); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.and_then(100) == cpp::fail(42)); - /// ``` - /// - /// \param value the value to return as a result - /// \return a result of \p value if this contains a value - template - RESULT_WARN_UNUSED - constexpr auto and_then(U&& value) const -> result::type,E>; - - /// \{ - /// \brief Invokes the function \p fn with the value of this result as - /// the argument - /// - /// If this result contains an error, a result of the error is returned - /// - /// The function being called must return a `result` type or the program - /// is ill-formed - /// - /// If this is called on an rvalue of `result` which contains an error, - /// the returned `result` is constructed from an rvalue of that error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto to_string(int) -> cpp::result; - /// auto r = cpp::result{42}; - /// assert(r.flat_map(to_string) == "42"); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.flat_map(to_string) == cpp::fail(42)); - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result of the function being called - template - RESULT_WARN_UNUSED - constexpr auto flat_map(Fn&& fn) const & -> detail::invoke_result_t; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t; - /// \} - - /// \{ - /// \brief Invokes the function \p fn with the value of this result as - /// the argument - /// - /// If this result is an error, the result of this function is that - /// error. Otherwise this function wraps the result and returns it as an - /// result. - /// - /// If this is called on an rvalue of `result` which contains an error, - /// the returned `result` is constructed from an rvalue of that error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto to_string(int) -> std::string; - /// auto r = cpp::result{42}; - /// assert(r.map(to_string) == "42"); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.map(to_string) == cpp::fail(42)); - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result result of the function invoked - template - RESULT_WARN_UNUSED - constexpr auto map(Fn&& fn) const & -> result,E>; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result,E>; - /// \} - - /// \{ - /// \brief Invokes the function \p fn with the error of this result as - /// the argument - /// - /// If this result contains a value, the result of this function is that - /// value. Otherwise the function is called with that error and returns the - /// result as a result. - /// - /// If this is called on an rvalue of `result` which contains a value, - /// the returned `result` is constructed from an rvalue of that value. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto to_string(int) -> std::string; - /// auto r = cpp::result{42}; - /// assert(r.map_error(to_string) == 42); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.map_error(to_string) == cpp::fail("42")); - /// - /// auto r = cpp::result{}; - /// auto s = r.map(std::string::size); // 's' contains 'result' - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result result of the function invoked - template - RESULT_WARN_UNUSED - constexpr auto map_error(Fn&& fn) - const & -> result>; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto map_error(Fn&& fn) - && -> result>; - /// \} - - /// \{ - /// \brief Invokes the function \p fn with the error of this result as - /// the argument - /// - /// If this result contains a value, a result of the value is returned - /// - /// The function being called must return a `result` type or the program - /// is ill-formed - /// - /// If this is called on an rvalue of `result` which contains an error, - /// the returned `result` is constructed from an rvalue of that error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto to_string(int) -> cpp::result; - /// auto r = cpp::result{42}; - /// assert(r.flat_map(to_string) == 42); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.flat_map(to_string) == cpp::fail("42")); - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result of the function being called - template - RESULT_WARN_UNUSED - constexpr auto flat_map_error(Fn&& fn) - const & -> detail::invoke_result_t; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn) - && -> detail::invoke_result_t; - /// \} - - //------------------------------------------------------------------------- - // Private Members - //------------------------------------------------------------------------- - private: - - detail::result_storage m_storage; - - //------------------------------------------------------------------------- - // Private Monadic Functions - //------------------------------------------------------------------------- - private: - - /// \{ - /// \brief Map implementations for void and non-void functions - /// - /// \param fn the function - template - constexpr auto map_impl(std::true_type, Fn&& fn) const & -> result; - template - constexpr auto map_impl(std::false_type, Fn&& fn) const & -> result,E>; - template - RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result; - template - RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result,E>; - /// \} - }; - - //=========================================================================== - // class : result - //=========================================================================== - - ///////////////////////////////////////////////////////////////////////////// - /// \brief Partial specialization of `result` - /// - /// \tparam E the underlying error type - ///////////////////////////////////////////////////////////////////////////// - template - class RESULT_NODISCARD result - { - // Type requirements - - static_assert( - !std::is_void::type>::value, - "It is ill-formed for E to be (possibly CV-qualified) void type" - ); - static_assert( - !std::is_abstract::value, - "It is ill-formed for E to be abstract type" - ); - static_assert( - !is_failure::type>::value, - "It is ill-formed for E to be a (possibly CV-qualified) 'failure' type" - ); - static_assert( - !std::is_reference::value, - "It is ill-formed for E to be a reference type. " - "Only T types may be lvalue references" - ); - - // Friendship - - friend detail::result_error_extractor; - - template - friend class result; - - //------------------------------------------------------------------------- - // Public Member Types - //------------------------------------------------------------------------- - public: - - using value_type = void; ///< The value type of this result - using error_type = E; ///< The error type of this result - using failure_type = failure; ///< The failure type - - template - using rebind = result; ///< Rebinds the result type - - //------------------------------------------------------------------------- - // Constructor / Assignment - //------------------------------------------------------------------------- - public: - - /// \brief Constructs a `result` object in a value state - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{}; - /// ``` - constexpr result() noexcept; - - /// \brief Copy constructs this result - /// - /// If other contains an error, constructs an object that contains a copy - /// of that error. - /// - /// \note This constructor is defined as deleted if - /// `std::is_copy_constructible::value` is `false` - /// - /// \note This constructor is defined as trivial if both - /// `std::is_trivially_copy_constructible::value` are `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// const auto r = cpp::result{}; - /// const auto s = r; - /// ``` - /// - /// \param other the result to copy - constexpr result(const result& other) = default; - - /// \brief Move constructs a result - /// - /// If other contains an error, move-constructs this result from that - /// error. - /// - /// \note This constructor is defined as deleted if - /// `std::is_move_constructible::value` is `false` - /// - /// \note This constructor is defined as trivial if both - /// `std::is_trivially_move_constructible::value` are `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{}; - /// auto s = std::move(r); - /// ``` - /// - /// \param other the result to move - constexpr result(result&& other) = default; - - /// \brief Converting copy constructor - /// - /// If \p other contains a value, constructs a result object that is not - /// in an error state -- ignoring the value. - /// - /// If \p other contains an error, constructs a result object that - /// contains an error, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type `E`. - /// - /// \note This constructor does not participate in overload resolution - /// unless the following conditions are met: - /// - `std::is_constructible_v` is `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// const auto r = cpp::result{42}; - /// const auto s = cpp::result{r}; - /// ``` - /// - /// \param other the other type to convert - template ::value>::type> - explicit result(const result& other) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Converting move constructor - /// - /// If \p other contains an error, constructs a result object that - /// contains an error, initialized as if direct-initializing - /// (but not direct-list-initializing) an object of type E&&. - /// - /// \note This constructor does not participate in overload resolution - /// unless the following conditions are met: - /// - `std::is_constructible_v` is `true` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{42}; - /// auto s = cpp::result{ - /// std::move(r) - /// }; - /// ``` - /// - /// \param other the other type to convert - template ::value>::type> - explicit result(result&& other) - noexcept(std::is_nothrow_constructible::value); - - //------------------------------------------------------------------------- - - /// \brief Constructs a result object in a value state - /// - /// This constructor exists primarily for symmetry with the `result` - /// constructor. Unlike the `T` overload, no variadic arguments may be - /// supplied. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{cpp::in_place}; - /// ``` - constexpr explicit result(in_place_t) noexcept; - - /// \brief Constructs a result object that contains an error - /// - /// the value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `E` from the arguments - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place_error, "Hello world" - /// }; - /// ``` - /// - /// \param args the arguments to pass to `E`'s constructor - template ::value>::type> - constexpr explicit result(in_place_error_t, Args&&... args) - noexcept(std::is_nothrow_constructible::value); - - /// \brief Constructs a result object that contains an error - /// - /// The value is initialized as if direct-initializing (but not - /// direct-list-initializing) an object of type `E` from the arguments - /// `std::forward>(ilist)`, - /// `std::forward(args)...` - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto r = cpp::result{ - /// cpp::in_place_error, {'H','e','l','l','o'} - /// }; - /// ``` - /// - /// \param ilist An initializer list of entries to forward - /// \param args the arguments to pass to Es constructor - template &, Args...>::value>::type> - constexpr explicit result(in_place_error_t, - std::initializer_list ilist, - Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value); - - //------------------------------------------------------------------------- - - /// \{ - /// \brief Constructs the underlying error of this result - /// - /// \note This constructor only participates in overload resolution if - /// `E` is constructible from \p e - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// cpp::result r = cpp::fail(42); - /// - /// auto get_error_result() -> cpp::result { - /// return cpp::fail("hello world!"); - /// } - /// ``` - /// - /// \param e the failure error - template ::value>::type> - constexpr /* implicit */ result(const failure& e) - noexcept(std::is_nothrow_constructible::value); - template ::value>::type> - constexpr /* implicit */ result(failure&& e) - noexcept(std::is_nothrow_constructible::value); - /// \} - - //------------------------------------------------------------------------- - - /// \brief Copy assigns the result stored in \p other - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_copy_constructible_v` is `true` - /// this restriction guarantees that no 'valueless_by_exception` state - /// may occur. - /// - /// \note This assignment operator is defined as trivial if the following - /// conditions are all `true`: - /// - `std::is_trivially_copy_constructible::value` - /// - `std::is_trivially_copy_assignable::value` - /// - `std::is_trivially_destructible::value` - /// - /// \param other the other result to copy - auto operator=(const result& other) -> result& = default; - - /// \brief Move assigns the result stored in \p other - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_copy_constructible_v` is `true` - /// this restriction guarantees that no 'valueless_by_exception` state - /// may occur. - /// - /// \note This assignment operator is defined as trivial if the following - /// conditions are all `true`: - /// - `std::is_trivially_move_constructible::value` - /// - `std::is_trivially_move_assignable::value` - /// - `std::is_trivially_destructible::value` - /// - /// \param other the other result to copy - auto operator=(result&& other) -> result& = default; - - /// \brief Copy-converts the state of \p other - /// - /// If both this and \p other contain an error, the underlying error is - /// assigned through copy-assignment. - /// - /// If \p other contains a value state, this result is constructed in a - /// value state. - /// - /// If \p other contans an error state, and this contains a value state, - /// the underlying error is constructed through copy-construction. - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v` are all `true`. - /// - /// \param other the other result object to convert - /// \return reference to `(*this)` - template ::value && - std::is_assignable::value>::type> - auto operator=(const result& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - - /// \brief Move-converts the state of \p other - /// - /// If both this and \p other contain an error, the underlying error is - /// assigned through move-assignment. - /// - /// If \p other contains a value state, this result is constructed in a - /// value state. - /// - /// If \p other contans an error state, and this contains a value state, - /// the underlying error is constructed through move-construction. - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v`, - /// `std::is_assignable_v` are all `true`. - /// - /// \param other the other result object to convert - /// \return reference to `(*this)` - template ::value && - std::is_assignable::value>::type> - auto operator=(result&& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - - /// \{ - /// \brief Perfect-forwarded assignment - /// - /// Depending on whether `*this` contains an error before the call, the - /// contained error is either direct-initialized via forwarding the error, - /// or assigned from forwarding the error - /// - /// \note The function does not participate in overload resolution unless - /// - `std::is_nothrow_constructible_v` is `true`, and - /// - `std::is_assignable_v` is `true` - /// - /// \param other the failure value to assign to this - /// \return reference to `(*this)` - template ::value>::type> - auto operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - template ::value>::type> - auto operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) -> result&; - /// \} - - //------------------------------------------------------------------------- - // Observers - //------------------------------------------------------------------------- - public: - - - /// \brief Contextually convertible to `true` if `*this` does not contain - /// an error - /// - /// This function exists to allow for simple, terse checks for containing - /// a value. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto get_result() -> cpp::result; - /// auto r = get_result(); - /// if (r) { ... } - /// - /// assert(static_cast(cpp::result{})); - /// - /// assert(!static_cast(cpp::result{cpp::fail(42)})); - /// ``` - /// - /// \return `true` if `*this` contains a value, `false` if `*this` - /// does not contain a value - RESULT_WARN_UNUSED - constexpr explicit operator bool() const noexcept; - - /// \copydoc result::has_value - RESULT_WARN_UNUSED - constexpr auto has_value() const noexcept -> bool; - - /// \copydoc result::has_error - RESULT_WARN_UNUSED - constexpr auto has_error() const noexcept -> bool; - - //------------------------------------------------------------------------- - - /// \{ - /// \brief Throws an exception if `(*this)` is in an error state - /// - /// This function exists for symmetry with `cpp::result` objects where - /// `T` contains a value. - /// - /// If this contains an error, an exception is thrown containing the - /// underlying error. The error is consumed propagating the same constness - /// and refness of this result. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// cpp::result{}.value(); // no exception - /// - /// auto r = cpp::result>{ - /// cpp::fail(std::make_unique(42)) - /// }; - /// std::move(r).value(); // throws bad_result_access> - /// - /// try { - /// auto r = cpp::result{ cpp::fail(42) }.value(); - /// } catch (const cpp::bad_result_access& e) { - /// assert(e.error() == 42); - /// } - /// ``` - /// - /// \throws bad_result_access if `*this` does not contain a value. - RESULT_CPP14_CONSTEXPR auto value() && -> void; - RESULT_CPP14_CONSTEXPR auto value() const & -> void; - /// \} - - /// \{ - /// \copydoc result::error - RESULT_WARN_UNUSED - constexpr auto error() const & - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E; - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto error() && - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E; - /// \} - - /// \{ - /// \copydoc result::expect - template ::value && - std::is_copy_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) const & -> void; - template ::value && - std::is_move_constructible::value - )>::type> - RESULT_CPP14_CONSTEXPR auto expect(String&& message) && -> void; - /// \} - - //------------------------------------------------------------------------- - // Monadic Functionalities - //------------------------------------------------------------------------- - public: - - /// \{ - /// \copydoc result::error_or - template - RESULT_WARN_UNUSED - constexpr auto error_or(U&& default_error) const & -> error_type; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto error_or(U&& default_error) && -> error_type; - /// \} - - //------------------------------------------------------------------------- - - /// \copydoc result::and_then - template - RESULT_WARN_UNUSED - constexpr auto and_then(U&& value) const -> result::type,E>; - - /// \{ - /// \brief Invokes the function \p fn if `(*this)` contains no value - /// - /// If this result contains an error, a result of the error is returned - /// - /// The function being called must return a `result` type or the program - /// is ill-formed - /// - /// If this is called on an rvalue of `result` which contains an error, - /// the returned `result` is constructed from an rvalue of that error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto generate_int() -> cpp::result { return 42; } - /// auto r = cpp::result{}; - /// assert(r.flat_map(generate_int) == 42); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.flat_map(generate_int) == cpp::fail(42)); - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result of the function being called - template - RESULT_WARN_UNUSED - constexpr auto flat_map(Fn&& fn) const & -> detail::invoke_result_t; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto flat_map(Fn&& fn) && -> detail::invoke_result_t; - /// \} - - /// \{ - /// \brief Invokes the function \p fn if `(*this)` contains no value - /// - /// If this result is an error, the result of this function is that - /// error. Otherwise this function wraps the result and returns it as an - /// result. - /// - /// If this is called on an rvalue of `result` which contains an error, - /// the returned `result` is constructed from an rvalue of that error. - /// - /// ### Examples - /// - /// Basic Usage: - /// - /// ```cpp - /// auto generate_int() -> int { return 42; } - /// auto r = cpp::result{}; - /// assert(r.map(generate_int) == 42); - /// - /// auto r = cpp::result{cpp::fail(42)}; - /// assert(r.map(generate_int) == cpp::fail(42)); - /// ``` - /// - /// \param fn the function to invoke with this - /// \return The result result of the function invoked - template - RESULT_WARN_UNUSED - constexpr auto map(Fn&& fn) const & -> result,E>; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto map(Fn&& fn) && -> result,E>; - /// \} - - /// \{ - /// \copydoc result::map_error - template - constexpr auto map_error(Fn&& fn) const & -> result>; - template - RESULT_CPP14_CONSTEXPR - auto map_error(Fn&& fn) && -> result>; - /// \} - - - /// \{ - /// \copydoc result::flat_map_error - template - RESULT_WARN_UNUSED - constexpr auto flat_map_error(Fn&& fn) const & -> detail::invoke_result_t; - template - RESULT_WARN_UNUSED - RESULT_CPP14_CONSTEXPR auto flat_map_error(Fn&& fn) && -> detail::invoke_result_t; - /// \} - - //------------------------------------------------------------------------- - // Private Members - //------------------------------------------------------------------------- - private: - - detail::result_storage m_storage; - - //------------------------------------------------------------------------- - // Private Monadic Functions - //------------------------------------------------------------------------- - private: - - /// \{ - /// \brief Map implementations for void and non-void functions - /// - /// \param fn the function - template - constexpr auto map_impl(std::true_type, Fn&& fn) const & -> result; - template - constexpr auto map_impl(std::false_type, Fn&& fn) const & -> result,E>; - template - RESULT_CPP14_CONSTEXPR auto map_impl(std::true_type, Fn&& fn) && -> result; - template - RESULT_CPP14_CONSTEXPR auto map_impl(std::false_type, Fn&& fn) && -> result,E>; - /// \} - }; - - //=========================================================================== - // non-member functions : class : result - //=========================================================================== - - //--------------------------------------------------------------------------- - // Comparison - //--------------------------------------------------------------------------- - - template - constexpr auto operator==(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator!=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator>=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator<=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator>(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator<(const result& lhs, const result& rhs) - noexcept -> bool; - - //--------------------------------------------------------------------------- - - template - constexpr auto operator==(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator!=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator>=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator<=(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator>(const result& lhs, const result& rhs) - noexcept -> bool; - template - constexpr auto operator<(const result& lhs, const result& rhs) - noexcept -> bool; - - //--------------------------------------------------------------------------- - - template ::value>::type> - constexpr auto operator==(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator==(const T& value, const result& exp) - noexcept -> bool; - template ::value>::type> - constexpr auto operator!=(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator!=(const T& value, const result& exp) - noexcept -> bool; - template ::value>::type> - constexpr auto operator<=(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator<=(const T& value, const result& exp) - noexcept -> bool; - template ::value>::type> - constexpr auto operator>=(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator>=(const T& value, const result& exp) - noexcept -> bool; - template ::value>::type> - constexpr auto operator<(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator<(const T& value, const result& exp) - noexcept -> bool; - template ::value>::type> - constexpr auto operator>(const result& exp, const U& value) - noexcept -> bool; - template ::value>::type> - constexpr auto operator>(const T& value, const result& exp) - noexcept -> bool; - - //--------------------------------------------------------------------------- - - template - constexpr auto operator==(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator==(const failure& value, const result& exp) - noexcept -> bool; - template - constexpr auto operator!=(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator!=(const failure& value, const result& exp) - noexcept -> bool; - template - constexpr auto operator<=(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator<=(const failure& value, const result& exp) - noexcept -> bool; - template - constexpr auto operator>=(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator>=(const failure& value, const result& exp) - noexcept -> bool; - template - constexpr auto operator<(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator<(const failure& value, const result& exp) - noexcept -> bool; - template - constexpr auto operator>(const result& exp, const failure& value) - noexcept -> bool; - template - constexpr auto operator>(const failure& value, const result& exp) - noexcept -> bool; - - //--------------------------------------------------------------------------- - // Utilities - //--------------------------------------------------------------------------- - - /// \{ - /// \brief Swaps the contents of \p lhs with \p rhs - /// - /// \param lhs the left result - /// \param rhs the right result - template - auto swap(result& lhs, result& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value && - std::is_nothrow_swappable::value && - std::is_nothrow_swappable::value) -#else - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value) -#endif - -> void; - template - auto swap(result& lhs, result& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value && - std::is_nothrow_swappable::value) -#else - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value) -#endif - -> void; - /// \} - -} // inline namespace bitwizeshift -} // namespace EXPECTED_NAMESPACE - -namespace std { - - template - struct hash<::RESULT_NS_IMPL::result> - { - auto operator()(const RESULT_NS_IMPL::result& x) const -> std::size_t - { - if (x.has_value()) { - return std::hash{}(*x) + 1; // add '1' to differentiate from error case - } - return std::hash{}(::RESULT_NS_IMPL::detail::extract_error(x)); - } - }; - - template - struct hash<::RESULT_NS_IMPL::result> - { - auto operator()(const RESULT_NS_IMPL::result& x) const -> std::size_t - { - if (x.has_value()) { - return 0; - } - return std::hash{}(::RESULT_NS_IMPL::detail::extract_error(x)); - } - }; - -} // namespace std - -#if !defined(RESULT_DISABLE_EXCEPTIONS) - -//============================================================================= -// class : bad_result_access -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructors -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::bad_result_access::bad_result_access(E2&& error) - : logic_error{"error attempting to access value from result containing error"}, - m_error(detail::forward(error)) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::bad_result_access::bad_result_access( - const char* what_arg, - E2&& error -) : logic_error{what_arg}, - m_error(detail::forward(error)) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::bad_result_access::bad_result_access( - const std::string& what_arg, - E2&& error -) : logic_error{what_arg}, - m_error(detail::forward(error)) -{ - -} - -//----------------------------------------------------------------------------- -// Observers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::bad_result_access::error() - & noexcept -> E& -{ - return m_error; -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::bad_result_access::error() - && noexcept -> E&& -{ - return static_cast(m_error); -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::bad_result_access::error() - const & noexcept -> const E& -{ - return m_error; -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::bad_result_access::error() - const && noexcept -> const E&& -{ - return static_cast(m_error); -} - -#endif - -//============================================================================= -// class : failure -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructors -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_failure(detail::forward(args)...) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure( - in_place_t, - std::initializer_list ilist, - Args&&...args -) noexcept(std::is_nothrow_constructible, Args...>::value) - : m_failure(ilist, detail::forward(args)...) -{ - -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure(E2&& error) - noexcept(std::is_nothrow_constructible::value) - : m_failure(detail::forward(error)) -{ - -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure(E2&& error) - noexcept(std::is_nothrow_constructible::value) - : m_failure(detail::forward(error)) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure(const failure& other) - noexcept(std::is_nothrow_constructible::value) - : m_failure(other.error()) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::failure::failure(failure&& other) - noexcept(std::is_nothrow_constructible::value) - : m_failure(static_cast&&>(other).error()) -{ - -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::failure::operator=(E2&& error) - noexcept( - std::is_nothrow_assignable::value || - std::is_lvalue_reference::value - ) -> failure& -{ - m_failure = detail::forward(error); - - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::failure::operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) - -> failure& -{ - m_failure = other.error(); - - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::failure::operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) - -> failure& -{ - m_failure = static_cast&&>(other).error(); - - return (*this); -} - -//----------------------------------------------------------------------------- -// Observers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::failure::error() - & noexcept -> typename std::add_lvalue_reference::type -{ - return m_failure; -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::failure::error() - && noexcept -> typename std::add_rvalue_reference::type -{ - using reference = typename std::add_rvalue_reference::type; - - return static_cast(m_failure); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::failure::error() - const & noexcept - -> typename std::add_lvalue_reference::type>::type -{ - return m_failure; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::failure::error() - const && noexcept - -> typename std::add_rvalue_reference::type>::type -{ - using reference = typename std::add_rvalue_reference::type>::type; - - return static_cast(m_failure); -} - -//============================================================================= -// non-member functions : class : failure -//============================================================================= - -//----------------------------------------------------------------------------- -// Comparison -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() == rhs.error(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() != rhs.error(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() < rhs.error(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() > rhs.error(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() <= rhs.error(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const failure& lhs, const failure& rhs) - noexcept -> bool -{ - return lhs.error() >= rhs.error(); -} - -//----------------------------------------------------------------------------- -// Utilities -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::fail(E&& e) - noexcept(std::is_nothrow_constructible::type,E>::value) - -> failure::type> -{ - using result_type = failure::type>; - - return result_type( - detail::forward(e) - ); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::fail(std::reference_wrapper e) - noexcept -> failure -{ - using result_type = failure; - - return result_type{e.get()}; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::fail(Args&&...args) - noexcept(std::is_nothrow_constructible::value) - -> failure -{ - return failure(in_place, detail::forward(args)...); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::fail(std::initializer_list ilist, Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value) - -> failure -{ - return failure(in_place, ilist, detail::forward(args)...); -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::swap(failure& lhs, failure& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_swappable::value) -> void -#else - noexcept(std::is_nothrow_move_constructible::value) - -> void -#endif -{ - using std::swap; - - swap(lhs.error(), rhs.error()); -} - -//============================================================================= -// class : detail::result_union -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructors / Assignment -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_union - ::result_union(unit) - noexcept - : m_empty{} -{ - // m_has_value intentionally not set -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::detail::result_union - ::result_union(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_value(detail::forward(args)...), - m_has_value{true} -{ -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::detail::result_union - ::result_union(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_error(detail::forward(args)...), - m_has_value{false} -{ -} - -//----------------------------------------------------------------------------- -// Modifiers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_union::destroy() - const noexcept -> void -{ - // do nothing -} - -//============================================================================= -// class : detail::result_union -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructors / Destructor / Assignment -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_union - ::result_union(unit) - noexcept - : m_empty{} -{ - // m_has_value intentionally not set -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::detail::result_union - ::result_union(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_value(detail::forward(args)...), - m_has_value{true} -{ -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::detail::result_union - ::result_union(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_error(detail::forward(args)...), - m_has_value{false} -{ -} - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_union - ::~result_union() - noexcept(std::is_nothrow_destructible::value && std::is_nothrow_destructible::value) -{ - destroy(); -} - -//----------------------------------------------------------------------------- -// Modifiers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_union::destroy() - -> void -{ - if (m_has_value) { - m_value.~underlying_value_type(); - } else { - m_error.~underlying_error_type(); - } -} - -//============================================================================= -// class : result_construct_base -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructors / Assignment -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_construct_base::result_construct_base(unit) - noexcept - : storage{unit{}} -{ -} - -template -template -inline constexpr RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_construct_base::result_construct_base( - in_place_t, - Args&&...args -) noexcept(std::is_nothrow_constructible::value) - : storage{in_place, detail::forward(args)...} -{ -} - -template -template -inline constexpr RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_construct_base::result_construct_base( - in_place_error_t, - Args&&...args -) noexcept(std::is_nothrow_constructible::value) - : storage(in_place_error, detail::forward(args)...) -{ -} - -//----------------------------------------------------------------------------- -// Construction / Assignment -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_value(Args&&...args) - noexcept(std::is_nothrow_constructible::value) - -> void -{ - using value_type = typename storage_type::underlying_value_type; - - auto* p = static_cast(std::addressof(storage.m_value)); - new (p) value_type(detail::forward(args)...); - storage.m_has_value = true; -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_error(Args&&...args) - noexcept(std::is_nothrow_constructible::value) - -> void -{ - using error_type = typename storage_type::underlying_error_type; - - auto* p = static_cast(std::addressof(storage.m_error)); - new (p) error_type(detail::forward(args)...); - storage.m_has_value = false; -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_error_from_result( - Result&& other -) -> void -{ - if (other.storage.m_has_value) { - construct_value(); - } else { - construct_error(detail::forward(other).storage.m_error); - } -} - - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_from_result( - Result&& other -) -> void -{ - if (other.storage.m_has_value) { - construct_value_from_result_impl( - std::is_lvalue_reference{}, - detail::forward(other).storage.m_value - ); - } else { - construct_error(detail::forward(other).storage.m_error); - } -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::assign_value(Value&& value) - noexcept(std::is_nothrow_assignable::value) - -> void -{ - if (!storage.m_has_value) { - storage.destroy(); - construct_value(detail::forward(value)); - } else { - storage.m_value = detail::forward(value); - } -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::assign_error(Error&& error) - noexcept(std::is_nothrow_assignable::value) - -> void -{ - if (storage.m_has_value) { - storage.destroy(); - construct_error(detail::forward(error)); - } else { - storage.m_error = detail::forward(error); - } -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::assign_from_result(Result&& other) - -> void -{ - if (other.storage.m_has_value != storage.m_has_value) { - storage.destroy(); - construct_from_result(detail::forward(other)); - } else if (storage.m_has_value) { - assign_value_from_result_impl( - std::is_lvalue_reference{}, - detail::forward(other) - ); - } else { - storage.m_error = detail::forward(other).storage.m_error; - } -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_value_from_result_impl( - std::true_type, - ReferenceWrapper&& reference -) noexcept -> void -{ - using value_type = typename storage_type::underlying_value_type; - - auto* p = static_cast(std::addressof(storage.m_value)); - new (p) value_type(reference.get()); - storage.m_has_value = true; -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::construct_value_from_result_impl( - std::false_type, - Value&& value -) noexcept(std::is_nothrow_constructible::value) -> void -{ - using value_type = typename storage_type::underlying_value_type; - - auto* p = static_cast(std::addressof(storage.m_value)); - new (p) value_type(detail::forward(value)); - storage.m_has_value = true; -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::assign_value_from_result_impl( - std::true_type, - Result&& other -) -> void -{ - // T is a reference; unwrap it - storage.m_value = other.storage.m_value.get(); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_construct_base::assign_value_from_result_impl( - std::false_type, - Result&& other -) -> void -{ - storage.m_value = detail::forward(other).storage.m_value; -} - - -//============================================================================= -// class : result_trivial_copy_ctor_base_impl -//============================================================================= - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_trivial_copy_ctor_base_impl - ::result_trivial_copy_ctor_base_impl(const result_trivial_copy_ctor_base_impl& other) - noexcept(std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_constructible::value) - : base_type(unit{}) -{ - using ctor_base = result_construct_base; - - ctor_base::construct_from_result(static_cast(other)); -} - -//============================================================================= -// class : result_trivial_move_ctor_base -//============================================================================= - -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::detail::result_trivial_move_ctor_base_impl - ::result_trivial_move_ctor_base_impl(result_trivial_move_ctor_base_impl&& other) - noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value) - : base_type(unit{}) -{ - using ctor_base = result_construct_base; - - ctor_base::construct_from_result(static_cast(other)); -} - -//============================================================================= -// class : result_copy_assign_base -//============================================================================= - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_trivial_copy_assign_base_impl - ::operator=(const result_trivial_copy_assign_base_impl& other) - noexcept(std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_constructible::value && - std::is_nothrow_copy_assignable::value && - std::is_nothrow_copy_assignable::value) - -> result_trivial_copy_assign_base_impl& -{ - using ctor_base = result_construct_base; - - ctor_base::assign_from_result(static_cast(other)); - return (*this); -} - -//========================================================================= -// class : result_move_assign_base -//========================================================================= - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::result_trivial_move_assign_base_impl - ::operator=(result_trivial_move_assign_base_impl&& other) - noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_assignable::value) - -> result_trivial_move_assign_base_impl& -{ - using ctor_base = result_construct_base; - - ctor_base::assign_from_result(static_cast(other)); - return (*this); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::detail::result_error_extractor::get(const result& exp) - noexcept -> const E& -{ - return exp.m_storage.storage.m_error; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::detail::result_error_extractor::get(result& exp) - noexcept -> E& -{ - return exp.m_storage.storage.m_error; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::detail::extract_error(const result& exp) noexcept -> const E& -{ - return result_error_extractor::get(exp); -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::throw_bad_result_access(E&& error) -> void -{ -#if defined(RESULT_DISABLE_EXCEPTIONS) - std::fprintf( - stderr, - "error attempting to access value from result containing error\n" - ); - std::abort(); -#else - using exception_type = bad_result_access< - typename std::remove_const< - typename std::remove_reference::type - >::type - >; - - throw exception_type{ - detail::forward(error) - }; -#endif -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::detail::throw_bad_result_access_message( - String&& message, - E&& error -) -> void -{ -#if defined(RESULT_DISABLE_EXCEPTIONS) - const auto message_string = std::string{ - detail::forward(message) - }; - std::fprintf(stderr, "%s\n", message_string.c_str()); - std::abort(); -#else - using exception_type = bad_result_access< - typename std::remove_const< - typename std::remove_reference::type - >::type - >; - - throw exception_type{ - detail::forward(message), - detail::forward(error) - }; -#endif -} - -//============================================================================= -// class : result -//============================================================================= - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result() - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place) -{ - -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(const result& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_from_result( - static_cast&>(other).m_storage - ); -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(const result& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_from_result( - static_cast&>(other).m_storage - ); -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(result&& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_from_result( - static_cast&&>(other).m_storage - ); -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(result&& other) - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_from_result( - static_cast&&>(other).m_storage - ); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(in_place_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place, detail::forward(args)...) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result( - in_place_t, - std::initializer_list ilist, - Args&&...args -) noexcept(std::is_nothrow_constructible, Args...>::value) - : m_storage(in_place, ilist, detail::forward(args)...) -{ - -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, detail::forward(args)...) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result( - in_place_error_t, - std::initializer_list ilist, - Args&&...args -) noexcept(std::is_nothrow_constructible, Args...>::value) - : m_storage(in_place_error, ilist, detail::forward(args)...) -{ - -} - -//------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(const failure& e) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, e.error()) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(failure&& e) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, static_cast(e.error())) -{ - -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(U&& value) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place, detail::forward(value)) -{ - -} - -template -template ::value,int>::type> -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(U&& value) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place, detail::forward(value)) -{ - -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(const result& other) - noexcept(std::is_nothrow_assignable::value && - std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_from_result( - static_cast&>(other).m_storage - ); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(result&& other) - noexcept(std::is_nothrow_assignable::value && - std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_from_result( - static_cast&&>(other).m_storage - ); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(U&& value) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_value(detail::forward(value)); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_error(other.error()); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_error(static_cast(other.error())); - return (*this); -} - -//----------------------------------------------------------------------------- -// Observers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::operator->() - noexcept -> typename std::remove_reference::type* -{ - // Prior to C++17, std::addressof was not `constexpr`. - // Since `addressof` fixes a relatively obscure issue where users define a - // custom `operator&`, the pre-C++17 implementation has been defined to be - // `&(**this)` so that it may exist in constexpr contexts. -#if __cplusplus >= 201703L - return std::addressof(**this); -#else - return &(**this); -#endif -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::operator->() - const noexcept -> typename std::remove_reference::type>::type* -{ -#if __cplusplus >= 201703L - return std::addressof(**this); -#else - return &(**this); -#endif -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::operator*() - & noexcept -> typename std::add_lvalue_reference::type -{ - return m_storage.storage.m_value; -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::operator*() - && noexcept -> typename std::add_rvalue_reference::type -{ - using reference = typename std::add_rvalue_reference::type; - - return static_cast(m_storage.storage.m_value); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::operator*() - const& noexcept -> typename std::add_lvalue_reference::type>::type -{ - return m_storage.storage.m_value; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::operator*() - const&& noexcept -> typename std::add_rvalue_reference::type>::type -{ - using reference = typename std::add_rvalue_reference::type>::type; - - return static_cast(m_storage.storage.m_value); -} - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::operator bool() - const noexcept -{ - return m_storage.storage.m_has_value; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::has_value() - const noexcept -> bool -{ - return m_storage.storage.m_has_value; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::has_error() - const noexcept -> bool -{ - return !m_storage.storage.m_has_value; -} - -//----------------------------------------------------------------------------- - -// The `has_value()` expression below is incorrectly identified as an unused -// value, which results in the `-Wunused-value` warning. This is suppressed -// to prevent false-positives -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-value" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-value" -#elif defined(_MSC_VER) -// Older MSVC versions incorrectly warn on returning a reference to a temporary. -// This has been suppressed -# pragma warning(push) -# pragma warning(disable:4172) -#endif - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::value() - & -> typename std::add_lvalue_reference::type -{ - return (has_value() || - (detail::throw_bad_result_access(m_storage.storage.m_error), false), - m_storage.storage.m_value - ); -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::value() - && -> typename std::add_rvalue_reference::type -{ - using reference = typename std::add_rvalue_reference::type; - - return (has_value() || - (detail::throw_bad_result_access(static_cast(m_storage.storage.m_error)), true), - static_cast(m_storage.storage.m_value) - ); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::value() - const & -> typename std::add_lvalue_reference::type>::type -{ - return (has_value() || - (detail::throw_bad_result_access(m_storage.storage.m_error), true), - m_storage.storage.m_value - ); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::value() - const && -> typename std::add_rvalue_reference::type>::type -{ - using reference = typename std::add_rvalue_reference::type>::type; - - return (has_value() || - (detail::throw_bad_result_access(static_cast(m_storage.storage.m_error)), true), - (static_cast(m_storage.storage.m_value)) - ); -} - -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER) -# pragma warning(pop) -#endif - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::error() const & - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E -{ - static_assert( - std::is_default_constructible::value, - "E must be default-constructible if 'error()' checks are used. " - "This is to allow for default-constructed error states to represent the " - "'good' state" - ); - - return m_storage.storage.m_has_value - ? E{} - : m_storage.storage.m_error; -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::error() && - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_move_constructible::value) -> E -{ - static_assert( - std::is_default_constructible::value, - "E must be default-constructible if 'error()' checks are used. " - "This is to allow for default-constructed error states to represent the " - "'good' state" - ); - - return m_storage.storage.m_has_value - ? E{} - : static_cast(m_storage.storage.m_error); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - & -> typename std::add_lvalue_reference::type -{ - return (has_value() || - (detail::throw_bad_result_access_message( - detail::forward(message), - m_storage.storage.m_error - ), true), - m_storage.storage.m_value - ); -} - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - && -> typename std::add_rvalue_reference::type -{ - using reference = typename std::add_rvalue_reference::type; - - return (has_value() || - (detail::throw_bad_result_access_message( - detail::forward(message), - static_cast(m_storage.storage.m_error) - ), true), - static_cast(m_storage.storage.m_value) - ); -} - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - const & -> typename std::add_lvalue_reference::type>::type -{ - return (has_value() || - (detail::throw_bad_result_access_message( - detail::forward(message), - m_storage.storage.m_error - ), true), - m_storage.storage.m_value - ); -} - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - const && -> typename std::add_rvalue_reference::type>::type -{ - using reference = typename std::add_rvalue_reference::type>::type; - - return (has_value() || - (detail::throw_bad_result_access_message( - detail::forward(message), - static_cast(m_storage.storage.m_error) - ), true), - (static_cast(m_storage.storage.m_value)) - ); -} - -//----------------------------------------------------------------------------- -// Monadic Functionalities -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::value_or(U&& default_value) - const& -> typename std::remove_reference::type -{ - return m_storage.storage.m_has_value - ? m_storage.storage.m_value - : detail::forward(default_value); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::value_or(U&& default_value) - && -> typename std::remove_reference::type -{ - return m_storage.storage.m_has_value - ? static_cast(**this) - : detail::forward(default_value); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::error_or(U&& default_error) - const& -> error_type -{ - return m_storage.storage.m_has_value - ? detail::forward(default_error) - : m_storage.storage.m_error; -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::error_or(U&& default_error) - && -> error_type -{ - return m_storage.storage.m_has_value - ? detail::forward(default_error) - : static_cast(m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::and_then(U&& value) - const -> result::type,E> -{ - return map([&value](const T&){ - return detail::forward(value); - }); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::flat_map(Fn&& fn) - const & -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map must return a result type or the program is ill-formed" - ); - - return has_value() - ? detail::invoke(detail::forward(fn), m_storage.storage.m_value) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::flat_map(Fn&& fn) - && -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map must return a result type or the program is ill-formed" - ); - - return has_value() - ? detail::invoke(detail::forward(fn), static_cast(m_storage.storage.m_value)) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map(Fn&& fn) - const & -> result,E> -{ - using result_type = detail::invoke_result_t; - - return map_impl(std::is_void{}, detail::forward(fn)); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map(Fn&& fn) - && -> result,E> -{ - using result_type = detail::invoke_result_t; - - return static_cast&&>(*this).map_impl( - std::is_void{}, - detail::forward(fn) - ); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_error(Fn&& fn) - const & -> result> -{ - using result_type = result>; - - return has_error() - ? result_type(in_place_error, detail::invoke( - detail::forward(fn), m_storage.storage.m_error - )) - : result_type(in_place, m_storage.storage.m_value); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_error(Fn&& fn) - && -> result> -{ - using result_type = result>; - - return has_error() - ? result_type(in_place_error, detail::invoke( - detail::forward(fn), static_cast(m_storage.storage.m_error) - )) - : result_type(static_cast(m_storage.storage.m_value)); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::flat_map_error(Fn&& fn) - const & -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map_error must return a result type or the program is ill-formed" - ); - - return has_value() - ? result_type(in_place, m_storage.storage.m_value) - : detail::invoke(detail::forward(fn), m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::flat_map_error(Fn&& fn) - && -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map_error must return a result type or the program is ill-formed" - ); - - return has_value() - ? result_type(in_place, static_cast(m_storage.storage.m_value)) - : detail::invoke(detail::forward(fn), static_cast(m_storage.storage.m_error)); -} - -//----------------------------------------------------------------------------- -// Private Monadic Functions -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_impl(std::true_type, Fn&& fn) - const & -> result -{ - using result_type = result; - - return has_value() - ? (detail::invoke(detail::forward(fn), m_storage.storage.m_value), result_type{}) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_impl(std::false_type, Fn&& fn) - const & -> result,E> -{ - using invoke_result_type = detail::invoke_result_t; - using result_type = result; - - return has_value() - ? result_type(in_place, detail::invoke( - detail::forward(fn), m_storage.storage.m_value - )) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_impl(std::true_type, Fn&& fn) - && -> result -{ - using result_type = result; - - return has_value() - ? (detail::invoke( - detail::forward(fn), static_cast(m_storage.storage.m_value) - ), result_type{}) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_impl(std::false_type, Fn&& fn) - && -> result,E> -{ - using invoke_result_type = detail::invoke_result_t; - using result_type = result; - - return has_value() - ? result_type(in_place, detail::invoke( - detail::forward(fn), static_cast(m_storage.storage.m_value) - )) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -//============================================================================= -// class : result -//============================================================================= - -//----------------------------------------------------------------------------- -// Constructor / Assignment -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result() - noexcept - : m_storage(in_place) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(const result& other) - noexcept(std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_error_from_result( - static_cast&>(other).m_storage - ); -} - -template -template -inline RESULT_INLINE_VISIBILITY -RESULT_NS_IMPL::result::result(result&& other) - noexcept(std::is_nothrow_constructible::value) - : m_storage(detail::unit{}) -{ - m_storage.construct_error_from_result( - static_cast&&>(other).m_storage - ); -} - - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(in_place_t) - noexcept - : m_storage(in_place) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(in_place_error_t, Args&&...args) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, detail::forward(args)...) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(in_place_error_t, - std::initializer_list ilist, - Args&&...args) - noexcept(std::is_nothrow_constructible, Args...>::value) - : m_storage(in_place_error, ilist, detail::forward(args)...) -{ - -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(const failure& e) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, e.error()) -{ - -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::result(failure&& e) - noexcept(std::is_nothrow_constructible::value) - : m_storage(in_place_error, static_cast(e.error())) -{ - -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(const result& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_from_result(other.m_storage); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(result&& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_from_result(static_cast&&>(other).m_storage); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(const failure& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_error(other.error()); - return (*this); -} - -template -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::result::operator=(failure&& other) - noexcept(std::is_nothrow_assignable::value) - -> result& -{ - m_storage.assign_error(static_cast(other.error())); - return (*this); -} - -//----------------------------------------------------------------------------- -// Observers -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -RESULT_NS_IMPL::result::operator bool() - const noexcept -{ - return has_value(); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::has_value() - const noexcept -> bool -{ - return m_storage.storage.m_has_value; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::has_error() - const noexcept -> bool -{ - return !has_value(); -} - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::value() - const & -> void -{ - static_cast( - has_value() || - (detail::throw_bad_result_access(m_storage.storage.m_error), true) - ); -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::value() - && -> void -{ - static_cast( - has_value() || - (detail::throw_bad_result_access(static_cast(m_storage.storage.m_error)), true) - ); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::error() - const & - noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E -{ - return has_value() ? E{} : m_storage.storage.m_error; -} - -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::error() - && noexcept(std::is_nothrow_constructible::value && - std::is_nothrow_copy_constructible::value) -> E -{ - return has_value() ? E{} : static_cast(m_storage.storage.m_error); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - const & -> void -{ - if (has_error()) { - detail::throw_bad_result_access_message( - detail::forward(message), - m_storage.storage.m_error - ); - } -} - -template -template -inline RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::expect(String&& message) - && -> void -{ - if (has_error()) { - detail::throw_bad_result_access_message( - detail::forward(message), - static_cast(m_storage.storage.m_error) - ); - } -} - -//----------------------------------------------------------------------------- -// Monadic Functionalities -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::error_or(U&& default_error) - const & -> error_type -{ - return has_value() - ? detail::forward(default_error) - : m_storage.storage.m_error; -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::error_or(U&& default_error) - && -> error_type -{ - return has_value() - ? detail::forward(default_error) - : static_cast(m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::and_then(U&& value) - const -> result::type,E> -{ - return map([&value]{ - return detail::forward(value); - }); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::flat_map(Fn&& fn) - const & -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map must return a result type or the program is ill-formed" - ); - - return has_value() - ? detail::invoke(detail::forward(fn)) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::flat_map(Fn&& fn) - && -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map must return a result type or the program is ill-formed" - ); - - return has_value() - ? detail::invoke(detail::forward(fn)) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map(Fn&& fn) - const & -> result,E> -{ - using result_type = detail::invoke_result_t; - - return map_impl(std::is_void{}, detail::forward(fn)); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map(Fn&& fn) - && -> result,E> -{ - using result_type = detail::invoke_result_t; - - return static_cast&&>(*this).map_impl( - std::is_void{}, - detail::forward(fn) - ); -} - -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_error(Fn&& fn) - const & -> result> -{ - using result_type = result>; - - return has_value() - ? result_type{} - : result_type(in_place_error, detail::invoke( - detail::forward(fn), m_storage.storage.m_error - )); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_error(Fn&& fn) - && -> result> -{ - using result_type = result>; - - return has_value() - ? result_type{} - : result_type(in_place_error, - detail::invoke(detail::forward(fn), static_cast(m_storage.storage.m_error) - )); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::flat_map_error(Fn&& fn) - const & -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map_error must return a result type or the program is ill-formed" - ); - static_assert( - std::is_default_constructible::value, - "flat_map_error for result requires the new T type to be default-" - "constructible" - ); - - return has_value() - ? result_type{} - : detail::invoke(detail::forward(fn), m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::flat_map_error(Fn&& fn) - && -> detail::invoke_result_t -{ - using result_type = detail::invoke_result_t; - - static_assert( - is_result::value, - "flat_map_error must return a result type or the program is ill-formed" - ); - static_assert( - std::is_default_constructible::value, - "flat_map_error for result requires the new T type to be default-" - "constructible" - ); - - return has_value() - ? result_type{} - : detail::invoke(detail::forward(fn), static_cast(m_storage.storage.m_error)); -} - -//----------------------------------------------------------------------------- -// Private Monadic Functions -//----------------------------------------------------------------------------- - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_impl(std::true_type, Fn&& fn) - const & -> result -{ - using result_type = result; - - return has_value() - ? (detail::invoke(detail::forward(fn)), result_type{}) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::result::map_impl(std::false_type, Fn&& fn) - const & -> result,E> -{ - using invoke_result_type = detail::invoke_result_t; - using result_type = result; - - return has_value() - ? result_type(in_place, detail::invoke(detail::forward(fn))) - : result_type(in_place_error, m_storage.storage.m_error); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_impl(std::true_type, Fn&& fn) - && -> result -{ - using result_type = result; - - return has_value() - ? (detail::invoke(detail::forward(fn)), result_type{}) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -template -template -inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR -auto RESULT_NS_IMPL::result::map_impl(std::false_type, Fn&& fn) - && -> result,E> -{ - using invoke_result_type = detail::invoke_result_t; - using result_type = result; - - return has_value() - ? result_type(in_place, detail::invoke(detail::forward(fn))) - : result_type(in_place_error, static_cast(m_storage.storage.m_error)); -} - -//============================================================================= -// non-member functions : class : result -//============================================================================= - -//----------------------------------------------------------------------------- -// Comparison -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs == *rhs - : detail::extract_error(lhs) == detail::extract_error(rhs) - ) - : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs != *rhs - : detail::extract_error(lhs) != detail::extract_error(rhs) - ) - : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs >= *rhs - : detail::extract_error(lhs) >= detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) >= static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs <= *rhs - : detail::extract_error(lhs) <= detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) <= static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs > *rhs - : detail::extract_error(lhs) > detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) > static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return (lhs.has_value() == rhs.has_value()) - ? ( - lhs.has_value() - ? *lhs < *rhs - : detail::extract_error(lhs) < detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) < static_cast(static_cast(rhs)); -} - - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? true - : detail::extract_error(lhs) == detail::extract_error(rhs) - ) - : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? false - : detail::extract_error(lhs) != detail::extract_error(rhs) - ) - : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? true - : detail::extract_error(lhs) >= detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) >= static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? true - : detail::extract_error(lhs) <= detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) <= static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? false - : detail::extract_error(lhs) > detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) > static_cast(static_cast(rhs)); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const result& lhs, - const result& rhs) - noexcept -> bool -{ - return lhs.has_value() == rhs.has_value() - ? ( - lhs.has_value() - ? false - : detail::extract_error(lhs) < detail::extract_error(rhs) - ) - : static_cast(static_cast(lhs)) < static_cast(static_cast(rhs)); -} - - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const result& exp, const U& value) - noexcept -> bool -{ - return (exp.has_value() && *exp == value); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const T& value, const result& exp) - noexcept -> bool -{ - return (exp.has_value() && *exp == value); -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const result& exp, const U& value) - noexcept -> bool -{ - return exp.has_value() ? *exp != value : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const T& value, const result& exp) - noexcept -> bool -{ - return exp.has_value() ? value != *exp : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const result& exp, const U& value) - noexcept -> bool -{ - return exp.has_value() ? *exp <= value : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const T& value, const result& exp) - noexcept -> bool -{ - return exp.has_value() ? value <= *exp : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const result& exp, const U& value) - noexcept -> bool -{ - return exp.has_value() ? *exp >= value : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const T& value, const result& exp) - noexcept -> bool -{ - return exp.has_value() ? value >= *exp : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const result& exp, const U& value) - noexcept -> bool -{ - return exp.has_value() ? *exp < value : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const T& value, const result& exp) - noexcept -> bool -{ - return exp.has_value() ? value < *exp : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const result& exp, const U& value) - noexcept -> bool -{ - return exp.has_value() ? *exp > value : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const T& value, const result& exp) - noexcept -> bool -{ - return exp.has_value() ? value > *exp : true; -} - -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) == error.error() : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator==(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() == detail::extract_error(exp) : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) != error.error() : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator!=(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() != detail::extract_error(exp) : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) <= error.error() : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<=(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() <= detail::extract_error(exp) : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) >= error.error() : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>=(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() >= detail::extract_error(exp) : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) < error.error() : true; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator<(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() < detail::extract_error(exp) : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const result& exp, const failure& error) - noexcept -> bool -{ - return exp.has_error() ? detail::extract_error(exp) > error.error() : false; -} - -template -inline RESULT_INLINE_VISIBILITY constexpr -auto RESULT_NS_IMPL::operator>(const failure& error, const result& exp) - noexcept -> bool -{ - return exp.has_error() ? error.error() > detail::extract_error(exp) : true; -} - -//----------------------------------------------------------------------------- -// Utilities -//----------------------------------------------------------------------------- - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::swap(result& lhs, result& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value && - std::is_nothrow_swappable::value && - std::is_nothrow_swappable::value) -#else - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value) -#endif - -> void -{ - using std::swap; - - if (lhs.has_value() == rhs.has_value()) { - if (lhs.has_value()) { - swap(*lhs, *rhs); - } else { - auto& lhs_error = detail::result_error_extractor::get(lhs); - auto& rhs_error = detail::result_error_extractor::get(rhs); - - swap(lhs_error, rhs_error); - } - // If both `result`s contain values, do nothing - } else { - auto temp = static_cast&&>(lhs); - lhs = static_cast&&>(rhs); - rhs = static_cast&&>(temp); - } -} - -template -inline RESULT_INLINE_VISIBILITY -auto RESULT_NS_IMPL::swap(result& lhs, result& rhs) -#if __cplusplus >= 201703L - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value && - std::is_nothrow_swappable::value) -#else - noexcept(std::is_nothrow_move_constructible>::value && - std::is_nothrow_move_assignable>::value) -#endif - -> void -{ - using std::swap; - - if (lhs.has_value() == rhs.has_value()) { - if (lhs.has_error()) { - auto& lhs_error = detail::result_error_extractor::get(lhs); - auto& rhs_error = detail::result_error_extractor::get(rhs); - - swap(lhs_error, rhs_error); - } - // If both `result`s contain values, do nothing - } else { - auto temp = static_cast&&>(lhs); - lhs = static_cast&&>(rhs); - rhs = static_cast&&>(temp); - } -} - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -#undef RESULT_NAMESPACE_INTERNAL -#undef RESULT_NS_IMPL -#undef RESULT_CPP14_CONSTEXPR -#undef RESULT_CPP17_INLINE -#undef RESULT_INLINE_VISIBILITY -#undef RESULT_NODISCARD -#undef RESULT_WARN_UNUSED - -#endif /* RESULT_RESULT_HPP */ \ No newline at end of file diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index 061d9edc..8bab1da5 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "../utils/Result.hpp" +#include #include "Log.hpp" #include "ModEvent.hpp" #include "ModMetadata.hpp" diff --git a/loader/include/Geode/loader/Mod.hpp b/loader/include/Geode/loader/Mod.hpp index 5639e628..8c78be4f 100644 --- a/loader/include/Geode/loader/Mod.hpp +++ b/loader/include/Geode/loader/Mod.hpp @@ -2,7 +2,7 @@ #include "../DefaultInclude.hpp" #include "../cocos/support/zip_support/ZipUtils.h" -#include "../utils/Result.hpp" +#include #include "../utils/VersionInfo.hpp" #include "../utils/general.hpp" diff --git a/loader/include/Geode/loader/ModMetadata.hpp b/loader/include/Geode/loader/ModMetadata.hpp index 9c0c553f..d6338448 100644 --- a/loader/include/Geode/loader/ModMetadata.hpp +++ b/loader/include/Geode/loader/ModMetadata.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../utils/Result.hpp" +#include #include "../utils/VersionInfo.hpp" #include "Types.hpp" diff --git a/loader/include/Geode/loader/Tulip.hpp b/loader/include/Geode/loader/Tulip.hpp index cecc986a..5de00c34 100644 --- a/loader/include/Geode/loader/Tulip.hpp +++ b/loader/include/Geode/loader/Tulip.hpp @@ -7,7 +7,7 @@ namespace geode::hook { /** * Create a calling convention wrapper for a function. */ - GEODE_DLL tulip::hook::Result createWrapper( + GEODE_DLL Result createWrapper( void* address, tulip::hook::WrapperMetadata const& metadata ) noexcept; diff --git a/loader/include/Geode/modify/Modify.hpp b/loader/include/Geode/modify/Modify.hpp index 6b79b7ed..a81ec8c4 100644 --- a/loader/include/Geode/modify/Modify.hpp +++ b/loader/include/Geode/modify/Modify.hpp @@ -158,7 +158,7 @@ namespace geode::modifier { for (auto& [uuid, hook] : m_hooks) { auto res = Mod::get()->claimHook(hook); if (!res) { - log::error("Failed to claim hook {}: {}", hook->getDisplayName(), res.error()); + log::error("Failed to claim hook {}: {}", hook->getDisplayName(), res.unwrapErr()); } else { added.push_back(uuid); diff --git a/loader/include/Geode/utils/JsonValidation.hpp b/loader/include/Geode/utils/JsonValidation.hpp index 7dd18a46..e54a16f7 100644 --- a/loader/include/Geode/utils/JsonValidation.hpp +++ b/loader/include/Geode/utils/JsonValidation.hpp @@ -4,7 +4,7 @@ #include "../loader/Log.hpp" #include #include -#include +#include namespace geode { struct JsonChecker; diff --git a/loader/include/Geode/utils/ObjcHook.hpp b/loader/include/Geode/utils/ObjcHook.hpp index ec52ae4f..dc1d2658 100644 --- a/loader/include/Geode/utils/ObjcHook.hpp +++ b/loader/include/Geode/utils/ObjcHook.hpp @@ -1,7 +1,7 @@ #pragma once #include "../loader/Hook.hpp" -#include "Result.hpp" +#include namespace geode { namespace hook { diff --git a/loader/include/Geode/utils/Result.hpp b/loader/include/Geode/utils/Result.hpp deleted file mode 100644 index b7ce5f71..00000000 --- a/loader/include/Geode/utils/Result.hpp +++ /dev/null @@ -1,305 +0,0 @@ -#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)); - } - - [[nodiscard]] constexpr decltype(auto) unwrapOrDefault() && requires std::is_default_constructible_v { - return this->Base::value_or(T()); - } - [[nodiscard]] constexpr decltype(auto) unwrapOrDefault() const& requires std::is_default_constructible_v { - return this->Base::value_or(T()); - } - - 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; - } - - /** - * Completely disregard the result. Only recommended if the result is - * inconsequential - */ - constexpr void disregard() && {} - }; - - 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) -} diff --git a/loader/include/Geode/utils/Task.hpp b/loader/include/Geode/utils/Task.hpp index 1d69b155..c2890be1 100644 --- a/loader/include/Geode/utils/Task.hpp +++ b/loader/include/Geode/utils/Task.hpp @@ -248,7 +248,7 @@ namespace geode { using Value = T; using Progress = P; - using PostResult = std::function; + using PostResult = std::function; using PostProgress = std::function; using HasBeenCancelled = std::function; using Run = std::function; diff --git a/loader/include/Geode/utils/VersionInfo.hpp b/loader/include/Geode/utils/VersionInfo.hpp index ce57ba71..d1f3e57f 100644 --- a/loader/include/Geode/utils/VersionInfo.hpp +++ b/loader/include/Geode/utils/VersionInfo.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "../utils/Result.hpp" +#include namespace geode { enum class VersionCompare { diff --git a/loader/include/Geode/utils/file.hpp b/loader/include/Geode/utils/file.hpp index 427c6de4..efb2199d 100644 --- a/loader/include/Geode/utils/file.hpp +++ b/loader/include/Geode/utils/file.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Result.hpp" +#include #include "general.hpp" #include "../loader/Event.hpp" #include "Task.hpp" diff --git a/loader/include/Geode/utils/general.hpp b/loader/include/Geode/utils/general.hpp index 8d84c4a0..a1912b5c 100644 --- a/loader/include/Geode/utils/general.hpp +++ b/loader/include/Geode/utils/general.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Result.hpp" +#include #include "../DefaultInclude.hpp" #include @@ -13,6 +13,7 @@ #include #include #include +#include namespace geode { using ByteVector = std::vector; @@ -159,6 +160,12 @@ namespace geode { */ GEODE_DLL float getDisplayFactor(); } + + template + requires (sizeof...(Args) > 0) + constexpr auto Err(fmt::format_string fmt, Args&&... args) { + return Err(fmt::format(fmt, std::forward(args)...)); + } } template<> diff --git a/loader/include/Geode/utils/map.hpp b/loader/include/Geode/utils/map.hpp index 3806dd8a..9a7b7bb8 100644 --- a/loader/include/Geode/utils/map.hpp +++ b/loader/include/Geode/utils/map.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Result.hpp" +#include #include #include diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index de421693..6f6f2a25 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -2,7 +2,7 @@ #include // another great circular dependency fix #include -#include "Result.hpp" +#include #include "Task.hpp" #include #include diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index a7810b77..54c938a4 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -496,20 +496,20 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) { thread::setName("Mod Unzip"); log::loadNest(nest); auto res = unzipFunction(); + auto prevNest = log::saveNest(); + log::loadNest(nest); + if (!res) { + this->addProblem({ + LoadProblem::Type::UnzipFailed, + node, + res.unwrapErr() + }); + log::error("Failed to unzip: {}", res.unwrapErr()); + m_refreshingModCount -= 1; + log::loadNest(prevNest); + return; + } this->queueInMainThread([=, this]() { - auto prevNest = log::saveNest(); - log::loadNest(nest); - if (!res) { - this->addProblem({ - LoadProblem::Type::UnzipFailed, - node, - res.unwrapErr() - }); - log::error("Failed to unzip: {}", res.unwrapErr()); - m_refreshingModCount -= 1; - log::loadNest(prevNest); - return; - } loadFunction(); log::loadNest(prevNest); }); diff --git a/loader/src/loader/LoaderImpl.hpp b/loader/src/loader/LoaderImpl.hpp index 99016566..7af233d5 100644 --- a/loader/src/loader/LoaderImpl.hpp +++ b/loader/src/loader/LoaderImpl.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include "ModImpl.hpp" diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 963925f4..ef237fe7 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -51,7 +51,9 @@ Result<> Mod::Impl::setup() { (void) utils::file::createDirectoryAll(m_saveDirPath); // always create temp dir for all mods, even if disabled, so resources can be loaded - GEODE_UNWRAP(this->createTempDir().expect("Unable to create temp dir: {error}")); + GEODE_UNWRAP(this->createTempDir().mapErr([](auto const& err) { + return fmt::format("Unable to create temp dir: {}", err); + })); m_settings = std::make_unique(m_metadata); auto loadRes = this->loadData(); diff --git a/loader/src/loader/ModMetadataImpl.cpp b/loader/src/loader/ModMetadataImpl.cpp index 0924187a..29e28c6f 100644 --- a/loader/src/loader/ModMetadataImpl.cpp +++ b/loader/src/loader/ModMetadataImpl.cpp @@ -307,8 +307,11 @@ Result ModMetadata::Impl::create(ModJson const& json) { if (json.contains("geode") && json["geode"].is_string()) { GEODE_UNWRAP_INTO( schema, - VersionInfo::parse(json["geode"].as_string()) - .expect("[mod.json] has invalid target loader version: {error}") + VersionInfo::parse(json["geode"].as_string()).mapErr( + [](auto const& err) { + return fmt::format("[mod.json] has invalid target loader version: {}", err); + } + ) ); } else { @@ -382,7 +385,9 @@ Result ModMetadata::Impl::createFromGeodeZip(file::Unzip& unzip) { // Read mod.json & parse if possible GEODE_UNWRAP_INTO( - auto jsonData, unzip.extract("mod.json").expect("Unable to read mod.json: {error}") + auto jsonData, unzip.extract("mod.json").mapErr([](auto const& err) { + return fmt::format("Unable to extract mod.json: {}", err); + }) ); std::string error; @@ -400,7 +405,9 @@ Result ModMetadata::Impl::createFromGeodeZip(file::Unzip& unzip) { auto impl = info.m_impl.get(); impl->m_path = unzip.getPath(); - GEODE_UNWRAP(info.addSpecialFiles(unzip).expect("Unable to add extra files: {error}")); + GEODE_UNWRAP(info.addSpecialFiles(unzip).mapErr([](auto const& err) { + return fmt::format("Unable to add extra files: {}", err); + })); return Ok(info); } @@ -409,7 +416,9 @@ Result<> ModMetadata::Impl::addSpecialFiles(file::Unzip& unzip) { // unzip known MD files for (auto& [file, target] : this->getSpecialFiles()) { if (unzip.hasEntry(file)) { - GEODE_UNWRAP_INTO(auto data, unzip.extract(file).expect("Unable to extract \"{}\"", file)); + GEODE_UNWRAP_INTO(auto data, unzip.extract(file).mapErr([&](auto const& err) { + return fmt::format("Unable to extract \"{}\": {}", file, err); + })); *target = sanitizeDetailsData(std::string(data.begin(), data.end())); } } diff --git a/loader/src/loader/ModSettingsManager.cpp b/loader/src/loader/ModSettingsManager.cpp index c908bb27..494a26da 100644 --- a/loader/src/loader/ModSettingsManager.cpp +++ b/loader/src/loader/ModSettingsManager.cpp @@ -8,22 +8,36 @@ using namespace geode::prelude; // #1 no need to duplicate the built-in settings between all mods // #2 easier lookup of custom settings if a mod uses another mod's custom setting type + +namespace { + auto changeToGenerator(auto&& function) { + return [function]( + std::string const& key, + std::string const& modID, + matjson::Value const& json + ) -> Result> { + return function(key, modID, json).map([](auto&& ptr) { + return std::shared_ptr(ptr); + }); + }; + } +} class SharedSettingTypesPool final { private: std::unordered_map m_types; SharedSettingTypesPool() : m_types({ - { "title", &TitleSetting::parse }, - { "bool", &BoolSetting::parse }, - { "int", &IntSetting::parse }, - { "float", &FloatSetting::parse }, - { "string", &StringSetting::parse }, - { "file", &FileSetting::parse }, - { "folder", &FileSetting::parse }, - { "path", &FileSetting::parse }, - { "rgb", &Color3BSetting::parse }, - { "color", &Color3BSetting::parse }, - { "rgba", &Color4BSetting::parse }, + { "title", changeToGenerator(TitleSettingV3::parse) }, + { "bool", changeToGenerator(BoolSettingV3::parse) }, + { "int", changeToGenerator(IntSettingV3::parse) }, + { "float", changeToGenerator(FloatSettingV3::parse) }, + { "string", changeToGenerator(StringSettingV3::parse) }, + { "file", changeToGenerator(FileSettingV3::parse) }, + { "folder", changeToGenerator(FileSettingV3::parse) }, + { "path", changeToGenerator(FileSettingV3::parse) }, + { "rgb", changeToGenerator(Color3BSettingV3::parse) }, + { "color", changeToGenerator(Color3BSettingV3::parse) }, + { "rgba", changeToGenerator(Color4BSettingV3::parse) }, }) {} public: @@ -135,7 +149,7 @@ public: continue; } if (auto v3 = (*gen)(key, modID, setting.json)) { - setting.v3 = *v3; + setting.v3 = v3.unwrap(); this->loadSettingValueFromSave(key); } else { diff --git a/loader/src/loader/PatchImpl.cpp b/loader/src/loader/PatchImpl.cpp index 38b331f1..4f30a73e 100644 --- a/loader/src/loader/PatchImpl.cpp +++ b/loader/src/loader/PatchImpl.cpp @@ -92,8 +92,8 @@ Result<> Patch::Impl::updateBytes(const ByteVector& bytes) { if (m_enabled) { auto res = this->disable(); if (!res) return Err("Failed to update patch: {}", res.unwrapErr()); - res = this->enable(); - if (!res) return Err("Failed to update patch: {}", res.unwrapErr()); + auto res2 = this->enable(); + if (!res2) return Err("Failed to update patch: {}", res2.unwrapErr()); } return Ok(); diff --git a/loader/src/loader/SettingV3.cpp b/loader/src/loader/SettingV3.cpp index 7f0d91b3..e4cb701c 100644 --- a/loader/src/loader/SettingV3.cpp +++ b/loader/src/loader/SettingV3.cpp @@ -152,18 +152,21 @@ namespace enable_if_parsing { return Ok(); } Result<> eval(std::string const& defaultModID) const override { - Result<> err = Ok(); + std::optional err; for (auto& comp : components) { auto res = comp->eval(defaultModID); if (res) { return Ok(); } // Only show first condition that isn't met - if (err.isOk()) { - err = Err(res.unwrapErr()); + if (!err.has_value()) { + err = res.unwrapErr(); } } - return err; + if (err.has_value()) { + return Err(*err); + } + return Ok(); } }; @@ -235,7 +238,10 @@ namespace enable_if_parsing { auto original = m_index; auto ret = this->nextWord(); m_index = original; - return ret ? *ret : std::nullopt; + if (!ret) { + return std::nullopt; + } + return ret.unwrap(); } Result> nextComponent() { GEODE_UNWRAP_INTO(auto maybeWord, this->nextWord()); diff --git a/loader/src/loader/Tulip.cpp b/loader/src/loader/Tulip.cpp index a21fd069..4d7bab6e 100644 --- a/loader/src/loader/Tulip.cpp +++ b/loader/src/loader/Tulip.cpp @@ -1,7 +1,9 @@ #include -tulip::hook::Result geode::hook::createWrapper( +using namespace geode::prelude; + +Result geode::hook::createWrapper( void* address, tulip::hook::WrapperMetadata const& metadata ) noexcept { diff --git a/loader/src/loader/updater.cpp b/loader/src/loader/updater.cpp index 10c12f8a..fa31dee1 100644 --- a/loader/src/loader/updater.cpp +++ b/loader/src/loader/updater.cpp @@ -83,7 +83,7 @@ void updater::fetchLatestGithubRelease( } else { Mod::get()->setSavedValue("last-modified-auto-update-check", response->header("Last-Modified").value_or("")); - s_latestGithubRelease = *json; + s_latestGithubRelease = json.unwrap(); then(*s_latestGithubRelease); } } @@ -141,7 +141,7 @@ void updater::tryDownloadLoaderResources(std::string const& url, bool tryLatestO // unzip resources zip auto unzip = file::Unzip::create(response->data()); if (unzip) { - auto ok = unzip->extractAllTo(resourcesDir); + auto ok = unzip.unwrap().extractAllTo(resourcesDir); if (ok) { updater::updateSpecialFiles(); ResourceDownloadEvent(UpdateFinished()).post(); @@ -308,7 +308,7 @@ void updater::downloadLoaderUpdate(std::string const& url) { // unzip resources zip auto unzip = file::Unzip::create(response->data()); if (unzip) { - auto ok = unzip->extractAllTo(targetDir); + auto ok = unzip.unwrap().extractAllTo(targetDir); if (ok) { s_isNewUpdateDownloaded = true; LoaderUpdateEvent(UpdateFinished()).post(); diff --git a/loader/src/platform/android/crashlog.cpp b/loader/src/platform/android/crashlog.cpp index 392b23e0..ae5bda51 100644 --- a/loader/src/platform/android/crashlog.cpp +++ b/loader/src/platform/android/crashlog.cpp @@ -261,12 +261,12 @@ int writeAndGetPid() { auto res = file::readString(pidFile); if (!res) { - log::warn("Failed to read last-pid file: {}", res.error()); + log::warn("Failed to read last-pid file: {}", res.unwrapErr()); } else { auto res = numFromString(res.unwrap()); if (!res) { - log::warn("Failed to parse last-pid file: {}", res.error()); + log::warn("Failed to parse last-pid file: {}", res.unwrapErr()); } else lastPid = res.unwrap(); } @@ -281,7 +281,7 @@ int writeAndGetPid() { auto res = file::writeString(pidFile, std::to_string(getpid())); if (!res) { - log::warn("Failed to write last-pid file: {}", res.error()); + log::warn("Failed to write last-pid file: {}", res.unwrapErr()); } return lastPid; diff --git a/loader/src/platform/android/util.cpp b/loader/src/platform/android/util.cpp index 549d9c51..6cd2bc09 100644 --- a/loader/src/platform/android/util.cpp +++ b/loader/src/platform/android/util.cpp @@ -12,7 +12,7 @@ using namespace geode::prelude; #include #include #include -#include +#include #include #include #include diff --git a/loader/src/platform/windows/nfdwin.hpp b/loader/src/platform/windows/nfdwin.hpp index 4602d0cc..d39c5fb1 100644 --- a/loader/src/platform/windows/nfdwin.hpp +++ b/loader/src/platform/windows/nfdwin.hpp @@ -41,7 +41,7 @@ #define NFD_UTF8_BOM "\xEF\xBB\xBF" #include -#include +#include #include using namespace geode::prelude; diff --git a/loader/src/platform/windows/util.cpp b/loader/src/platform/windows/util.cpp index d5020657..7e9322f0 100644 --- a/loader/src/platform/windows/util.cpp +++ b/loader/src/platform/windows/util.cpp @@ -120,7 +120,6 @@ Task> file::pick(PickMode mode, FilePickOptions co return RetTask::immediate(Err("Invalid pick mode")); } std::filesystem::path path; - Result result; auto pickresult = nfdPick(nfdMode, options, &path); if (pickresult.isErr()) { if (pickresult.unwrapErr() == "Dialog cancelled") { @@ -137,13 +136,11 @@ Task>> file::pickMany(FilePickOptions std::vector paths; auto pickResult = nfdPick(NFDMode::OpenFiles, options, &paths); - Result> result; if (pickResult.isErr()) { - result = Err(pickResult.err().value()); + return RetTask::immediate(Err(pickResult.err().value())); } else { - result = Ok(paths); + return RetTask::immediate(Ok(paths)); } - return RetTask::immediate(std::move(result)); // return Task>>::immediate(std::move(file::pickFiles(options))); } diff --git a/loader/src/server/Server.cpp b/loader/src/server/Server.cpp index 43a9e08a..ed53871f 100644 --- a/loader/src/server/Server.cpp +++ b/loader/src/server/Server.cpp @@ -783,7 +783,7 @@ void server::queueBatches( ) { // we have to do the copy here, or else our values die batchedCheckUpdates(batches->back()).listen([resolve, batches, accum](auto result) { - if (result->ok()) { + if (result->isOk()) { auto serverValues = result->unwrap(); accum->reserve(accum->size() + serverValues.size()); @@ -798,7 +798,12 @@ void server::queueBatches( } } else { - resolve(*result); + if (result->isOk()) { + resolve(Ok(result->unwrap())); + } + else { + resolve(Err(result->unwrapErr())); + } } }); } diff --git a/loader/src/ui/GeodeUI.cpp b/loader/src/ui/GeodeUI.cpp index dff7dff6..a7621074 100644 --- a/loader/src/ui/GeodeUI.cpp +++ b/loader/src/ui/GeodeUI.cpp @@ -34,7 +34,7 @@ protected: if (auto res = event->getValue()) { if (res->isOk()) { // Copy info first as onClose may free the listener which will free the event - auto info = **res; + auto info = res->unwrap(); this->onClose(nullptr); // Run this on next frame because otherwise the popup is unable to call server::getMod for some reason Loader::get()->queueInMainThread([info = std::move(info)]() mutable { diff --git a/loader/src/ui/mods/sources/ModSource.cpp b/loader/src/ui/mods/sources/ModSource.cpp index fe7bb2e0..0860ee73 100644 --- a/loader/src/ui/mods/sources/ModSource.cpp +++ b/loader/src/ui/mods/sources/ModSource.cpp @@ -14,9 +14,9 @@ LoadModSuggestionTask loadModSuggestion(LoadProblem const& problem) { if (auto suggestionVersionRes = ComparableVersionInfo::parse(suggestionVersionStr)) { server::ModVersion suggestionVersion = server::ModVersionLatest(); - if (suggestionVersionRes->getComparison() == VersionCompare::MoreEq) { + if (suggestionVersionRes.unwrap().getComparison() == VersionCompare::MoreEq) { suggestionVersion = server::ModVersionMajor { - .major = suggestionVersionRes->getUnderlyingVersion().getMajor() + .major = suggestionVersionRes.unwrap().getUnderlyingVersion().getMajor() }; } // todo: if mods are allowed to specify other type of version comparisons in the future, @@ -195,7 +195,7 @@ server::ServerRequest> ModSource::fetchValidTags } return Ok(finalTags); } - return *result; + return Ok(result->unwrap()); }, [](server::ServerProgress* progress) { return *progress; diff --git a/loader/src/ui/nodes/MDTextArea.cpp b/loader/src/ui/nodes/MDTextArea.cpp index e02d1a0d..df27a2e7 100644 --- a/loader/src/ui/nodes/MDTextArea.cpp +++ b/loader/src/ui/nodes/MDTextArea.cpp @@ -329,19 +329,19 @@ struct MDParser { if (key == "scale") { auto scaleRes = utils::numFromString(value); if (scaleRes) { - spriteScale = *scaleRes; + spriteScale = scaleRes.unwrap(); } } else if (key == "width") { auto widthRes = utils::numFromString(value); if (widthRes) { - spriteWidth = *widthRes; + spriteWidth = widthRes.unwrap(); } } else if (key == "height") { auto heightRes = utils::numFromString(value); if (heightRes) { - spriteHeight = *heightRes; + spriteHeight = heightRes.unwrap(); } } } diff --git a/loader/src/utils/file.cpp b/loader/src/utils/file.cpp index cecd1254..caeba44e 100644 --- a/loader/src/utils/file.cpp +++ b/loader/src/utils/file.cpp @@ -57,7 +57,7 @@ Result utils::file::readJson(std::filesystem::path const& path) if (!str) return Err(str.unwrapErr()); std::string error; - auto res = matjson::parse(str.value(), error); + auto res = matjson::parse(str.unwrap(), error); if (error.size()) return Err("Unable to parse JSON: " + error); return Ok(res.value()); @@ -304,7 +304,9 @@ public: GEODE_UNWRAP( mzTry(mz_zip_entry_read_open(m_handle, 0, nullptr)) - .expect("Unable to open entry (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to open entry (code {})", error); + }) ); // if the file is empty, its data is empty (duh) @@ -323,7 +325,9 @@ public: mz_zip_entry_close(m_handle); GEODE_UNWRAP(file::createDirectoryAll((dir / name).parent_path())); - GEODE_UNWRAP(file::writeBinary(dir / name, res).expect("Unable to write to {}: {error}", dir / name)); + GEODE_UNWRAP(file::writeBinary(dir / name, res).mapErr([&](auto error) { + return fmt::format("Unable to write to {}: {}", dir / name, error); + })); return Ok(); } @@ -333,14 +337,18 @@ public: GEODE_UNWRAP( mzTry(mz_zip_goto_first_entry(m_handle)) - .expect("Unable to navigate to first entry (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to navigate to first entry (code {})", error); + }) ); uint64_t numEntries; GEODE_UNWRAP( mzTry(mz_zip_get_number_entry(m_handle, &numEntries)) - .expect("Unable to get number of entries (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to get number of entries (code {})", error); + }) ); uint32_t currentEntry = 0; @@ -395,7 +403,9 @@ public: GEODE_UNWRAP( mzTry(mz_zip_goto_first_entry(m_handle)) - .expect("Unable to navigate to first entry (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to navigate to first entry (code {})", error); + }) ); GEODE_UNWRAP( @@ -403,12 +413,17 @@ public: m_handle, reinterpret_cast(name.u8string().c_str()), 1 - )).expect("Unable to navigate to entry (code {error})") + )) + .mapErr([&](auto error) { + return fmt::format("Unable to locate entry (code {})", error); + }) ); GEODE_UNWRAP( mzTry(mz_zip_entry_read_open(m_handle, 0, nullptr)) - .expect("Unable to open entry (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to open entry (code {})", error); + }) ); // if the file is empty, its data is empty (duh) @@ -448,7 +463,9 @@ public: GEODE_UNWRAP( mzTry(mz_zip_entry_write_open(m_handle, &info, MZ_COMPRESS_LEVEL_DEFAULT, 0, nullptr)) - .expect("Unable to open entry for writing (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to open entry for writing (code {})", error); + }) ); mz_zip_entry_close(m_handle); @@ -465,7 +482,9 @@ public: GEODE_UNWRAP( mzTry(mz_zip_entry_write_open(m_handle, &info, MZ_COMPRESS_LEVEL_DEFAULT, 0, nullptr)) - .expect("Unable to open entry for writing (code {error})") + .mapErr([&](auto error) { + return fmt::format("Unable to open entry for writing (code {})", error); + }) ); auto written = mz_zip_entry_write(m_handle, data.data(), data.size()); if (written < 0) { @@ -550,16 +569,22 @@ bool Unzip::hasEntry(Path const& name) { } Result Unzip::extract(Path const& name) { - return m_impl->extract(name).expect("{error} (entry {})", name.string()); + return m_impl->extract(name).mapErr([&](auto error) { + return fmt::format("Unable to extract entry {}: {}", name.string(), error); + }); } Result<> Unzip::extractTo(Path const& name, Path const& path) { - GEODE_UNWRAP_INTO(auto bytes, m_impl->extract(name).expect("{error} (entry {})", name.string())); + GEODE_UNWRAP_INTO(auto bytes, m_impl->extract(name).mapErr([&](auto error) { + return fmt::format("Unable to extract entry {}: {}", name.string(), error); + })); // create containing directories for target path if (path.has_parent_path()) { GEODE_UNWRAP(file::createDirectoryAll(path.parent_path())); } - GEODE_UNWRAP(file::writeBinary(path, bytes).expect("Unable to write file {}: {error}", path.string())); + GEODE_UNWRAP(file::writeBinary(path, bytes).mapErr([&](auto error) { + return fmt::format("Unable to write file {}: {}", path.string(), error); + })); return Ok(); } diff --git a/loader/src/utils/web.cpp b/loader/src/utils/web.cpp index 02028859..fe3dc7c1 100644 --- a/loader/src/utils/web.cpp +++ b/loader/src/utils/web.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -498,7 +498,7 @@ WebRequest& WebRequest::header(std::string_view name, std::string_view value) { int timeoutValue = 5; auto res = numFromString(value.substr(numStart, numLength)); if (res) { - timeoutValue = res.value(); + timeoutValue = res.unwrap(); } timeout(std::chrono::seconds(timeoutValue));