#ifndef MAMBA_ERROR_HANDLING_HPP #define MAMBA_ERROR_HANDLING_HPP #include #include #include #include #include "tl/expected.hpp" namespace mamba { /********************* * Mamba exceptions * *********************/ enum class mamba_error_code { unknown, aggregated, prefix_data_not_loaded, subdirdata_not_loaded, cache_not_loaded, repodata_not_loaded, configurable_bad_cast, env_lockfile_parsing_failed, openssl_failed, internal_failure, lockfile_failure, selfupdate_failure, satisfiablitity_error, user_interrupted, incorrect_usage, invalid_spec, download_content }; class mamba_error : public std::runtime_error { public: using base_type = std::runtime_error; mamba_error(const std::string& msg, mamba_error_code ec); mamba_error(const char* msg, mamba_error_code ec); mamba_error(const std::string& msg, mamba_error_code ec, std::any&& data); mamba_error(const char* msg, mamba_error_code ec, std::any&& data); mamba_error_code error_code() const noexcept; const std::any& data() const noexcept; private: mamba_error_code m_error_code; std::any m_data; }; class mamba_aggregated_error : public mamba_error { public: using base_type = mamba_error; using error_list_t = std::vector; explicit mamba_aggregated_error(error_list_t&& error_list); const char* what() const noexcept override; private: error_list_t m_error_list; mutable std::string m_aggregated_message; static constexpr const char* m_base_message = "Multiple errors occurred:\n"; }; /******************************** * wrappers around tl::expected * ********************************/ template class expected_ref_wrapper : private tl::expected, E> { public: using value_type = T; using self_type = expected_ref_wrapper; using reference = std::reference_wrapper; using base_type = tl::expected; using base_type::base_type; using base_type::operator=; using base_type::emplace; using base_type::error; using base_type::operator bool; using base_type::has_value; constexpr void swap(self_type& rhs) noexcept; constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept; constexpr const T& operator*() const& noexcept; constexpr T& operator*() & noexcept; constexpr const T&& operator*() const&& noexcept; constexpr T&& operator*() && noexcept; constexpr T& value() &; constexpr const T&& value() const&&; constexpr T&& value() &&; template constexpr T value_or(U&&) const&; template constexpr T value_or(U&&) &&; template friend constexpr bool operator==(const self_type& x, const expected_ref_wrapper& y); template friend constexpr bool operator==(const self_type&, const T2&); template friend constexpr bool operator==(const self_type&, const tl::unexpected&); }; namespace detail { template struct get_expected { using type = tl::expected; }; template struct get_expected { using type = expected_ref_wrapper; }; } template using expected_t = typename detail::get_expected::type; /******************** * helper functions * ********************/ tl::unexpected make_unexpected(const char* msg, mamba_error_code ec); tl::unexpected make_unexpected(const std::string& msg, mamba_error_code sc); tl::unexpected make_unexpected(std::vector&& error_list); template tl::unexpected forward_error(const tl::expected& exp); template tl::unexpected forward_error(const expected_ref_wrapper& exp); template T& extract(tl::expected& exp); template const T& extract(const tl::expected& exp); template T&& extract(tl::expected&& exp); template T& extract(expected_ref_wrapper& exp); template const T& extract(const expected_ref_wrapper& exp); template T&& extract(expected_ref_wrapper&& exp); /*************************************** * expected_ref_wrapper implementation * ***************************************/ template constexpr void expected_ref_wrapper::swap(self_type& rhs) noexcept { base_type::swap(rhs); } template constexpr const T* expected_ref_wrapper::operator->() const noexcept { return &(base_type::operator->()->get()); } template constexpr T* expected_ref_wrapper::operator->() noexcept { return &(base_type::operator->()->get()); } template constexpr const T& expected_ref_wrapper::operator*() const& noexcept { return base_type::operator*().get(); } template constexpr T& expected_ref_wrapper::operator*() & noexcept { return base_type::operator*().get(); } template constexpr const T&& expected_ref_wrapper::operator*() const&& noexcept { return std::move(base_type::operator*().get()); } template constexpr T&& expected_ref_wrapper::operator*() && noexcept { return std::move(base_type::operator*().get()); } template constexpr T& expected_ref_wrapper::value() & { return base_type::value().get(); } template constexpr const T&& expected_ref_wrapper::value() const&& { return std::move(base_type::value().get()); } template constexpr T&& expected_ref_wrapper::value() && { return std::move(base_type::value().get()); } template template constexpr T expected_ref_wrapper::value_or(U&& u) const& { return base_type::value_or(std::move(u)).get(); } template template constexpr T expected_ref_wrapper::value_or(U&& u) && { return base_type::value_or(std::move(u)).get(); } template constexpr bool operator==(const expected_ref_wrapper& x, const expected_ref_wrapper& y) { using base_type1 = typename expected_ref_wrapper::base_type; using base_type2 = typename expected_ref_wrapper::base_type; return operator==(static_cast(x), static_cast(y)); } template constexpr bool operator==(const expected_ref_wrapper& x, const T2& y) { using base_type1 = typename expected_ref_wrapper::base_type; return operator==(static_cast(x), y); } template constexpr bool operator==(const expected_ref_wrapper& x, const tl::unexpected& y) { using base_type1 = typename expected_ref_wrapper::base_type; return operator==(static_cast(x), y); } /*********************************** * helper functions implementation * ***********************************/ template tl::unexpected forward_error(const tl::expected& exp) { return tl::make_unexpected(exp.error()); } template tl::unexpected forward_error(const expected_ref_wrapper& exp) { return tl::make_unexpected(exp.error()); } namespace detail { template decltype(auto) extract_impl(T&& exp) { if (exp) { return std::forward(exp).value(); } else { throw exp.error(); } } } template T& extract(tl::expected& exp) { return detail::extract_impl(exp); } template const T& extract(const tl::expected& exp) { return detail::extract_impl(exp); } template T&& extract(tl::expected&& exp) { return detail::extract_impl(std::move(exp)); } template T& extract(expected_ref_wrapper& exp) { return detail::extract_impl(exp); } template const T& extract(const expected_ref_wrapper& exp) { return detail::extract_impl(exp); } template T&& extract(expected_ref_wrapper&& exp) { return detail::extract_impl(std::move(exp)); } } #endif