#ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED #define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED // Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include namespace boost { namespace leaf { template class BOOST_LEAF_SYMBOL_VISIBLE result; //////////////////////////////////////// #ifndef BOOST_LEAF_NO_EXCEPTIONS namespace detail { inline error_id unpack_error_id(std::exception const & ex) noexcept { if( detail::exception_base const * eb = dynamic_cast(&ex) ) return eb->get_error_id(); if( error_id const * err_id = dynamic_cast(&ex) ) return *err_id; return current_error(); } } #endif //////////////////////////////////////// class BOOST_LEAF_SYMBOL_VISIBLE error_info { error_info & operator=( error_info const & ) = delete; error_id const err_id_; #ifndef BOOST_LEAF_NO_EXCEPTIONS std::exception * const ex_; #endif e_source_location const * const loc_; protected: error_info( error_info const & ) noexcept = default; public: BOOST_LEAF_CONSTEXPR error_info(error_id id, std::exception * ex, e_source_location const * loc) noexcept: err_id_(id), #ifndef BOOST_LEAF_NO_EXCEPTIONS ex_(ex), #endif loc_(loc) { (void) ex; } BOOST_LEAF_CONSTEXPR error_id error() const noexcept { return err_id_; } BOOST_LEAF_CONSTEXPR std::exception * exception() const noexcept { #ifdef BOOST_LEAF_NO_EXCEPTIONS return nullptr; #else return ex_; #endif } BOOST_LEAF_CONSTEXPR e_source_location const * source_location() const noexcept { return loc_; } template void print_error_info(std::basic_ostream & os) const { os << "Error with serial #" << err_id_; if( loc_ ) os << " reported at " << *loc_; #ifndef BOOST_LEAF_NO_EXCEPTIONS if( ex_ ) { os << "\nCaught:" BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER; #if BOOST_LEAF_CFG_DIAGNOSTICS if( auto eb = dynamic_cast(ex_) ) eb->print_type_name(os); else #endif detail::demangle_and_print(os, typeid(*ex_).name()); os << ": \"" << ex_->what() << '"'; } #endif } template friend std::ostream & operator<<(std::basic_ostream & os, error_info const & x) { x.print_error_info(os); return os << '\n'; } }; namespace detail { template <> struct handler_argument_traits: handler_argument_always_available<> { template BOOST_LEAF_CONSTEXPR static error_info const & get(Tup const &, error_info const & ei) noexcept { return ei; } }; } //////////////////////////////////////// namespace detail { template struct type_index; template struct type_index { constexpr static int value = 0; }; template struct type_index { constexpr static int value = 1 + type_index::value; }; template struct tuple_type_index; template struct tuple_type_index> { constexpr static int value = type_index::value; }; #ifndef BOOST_LEAF_NO_EXCEPTIONS template ::value> struct peek_exception; template <> struct peek_exception { BOOST_LEAF_CONSTEXPR static std::exception const * peek( error_info const & ei ) noexcept { return ei.exception(); } }; template <> struct peek_exception { BOOST_LEAF_CONSTEXPR static std::exception * peek( error_info const & ei ) noexcept { return ei.exception(); } }; #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <> struct peek_exception { static std::error_code const * peek( error_info const & ei ) noexcept { auto const ex = ei.exception(); if( std::system_error * se = dynamic_cast(ex) ) return &se->code(); else if( std::error_code * ec = dynamic_cast(ex) ) return ec; else return nullptr; } }; template <> struct peek_exception { static std::error_code * peek( error_info const & ei ) noexcept { auto const ex = ei.exception(); if( std::system_error * se = dynamic_cast(ex) ) return const_cast(&se->code()); else if( std::error_code * ec = dynamic_cast(ex) ) return ec; else return nullptr; } }; #endif template struct peek_exception { static E * peek( error_info const & ei ) noexcept { return dynamic_cast(ei.exception()); } }; template struct peek_exception { BOOST_LEAF_CONSTEXPR static E * peek( error_info const & ) noexcept { return nullptr; } }; #endif template ::value> struct peek_tuple; template struct peek_tuple { template BOOST_LEAF_CONSTEXPR static E const * peek( SlotsTuple const &, error_id const & ) noexcept { return nullptr; } template BOOST_LEAF_CONSTEXPR static E * peek( SlotsTuple &, error_id const & ) noexcept { return nullptr; } }; template struct peek_tuple { template BOOST_LEAF_CONSTEXPR static E const * peek( SlotsTuple const & tup, error_id const & err ) noexcept { return std::get,SlotsTuple>::value>(tup).has_value(err.value()); } template BOOST_LEAF_CONSTEXPR static E * peek( SlotsTuple & tup, error_id const & err ) noexcept { return std::get,SlotsTuple>::value>(tup).has_value(err.value()); } }; template BOOST_LEAF_CONSTEXPR inline E const * peek( SlotsTuple const & tup, error_info const & ei ) noexcept { if( error_id err = ei.error() ) { if( E const * e = peek_tuple::peek(tup, err) ) return e; #ifndef BOOST_LEAF_NO_EXCEPTIONS else return peek_exception::peek(ei); #endif } return nullptr; } template BOOST_LEAF_CONSTEXPR inline E * peek( SlotsTuple & tup, error_info const & ei ) noexcept { if( error_id err = ei.error() ) { if( E * e = peek_tuple::peek(tup, err) ) return e; #ifndef BOOST_LEAF_NO_EXCEPTIONS else return peek_exception::peek(ei); #endif } return nullptr; } } //////////////////////////////////////// namespace detail { template template BOOST_LEAF_CONSTEXPR inline typename handler_argument_traits_defaults::error_type const * handler_argument_traits_defaults:: check( Tup const & tup, error_info const & ei ) noexcept { return peek::type>(tup, ei); } template template BOOST_LEAF_CONSTEXPR inline typename handler_argument_traits_defaults::error_type * handler_argument_traits_defaults:: check( Tup & tup, error_info const & ei ) noexcept { return peek::type>(tup, ei); } template BOOST_LEAF_CONSTEXPR inline std::exception const * handler_argument_traits:: check( Tup const &, error_info const & ei ) noexcept { return ei.exception(); } template struct check_arguments; template struct check_arguments { BOOST_LEAF_CONSTEXPR static bool check( Tup const &, error_info const & ) { return true; } }; template struct check_arguments { BOOST_LEAF_CONSTEXPR static bool check( Tup & tup, error_info const & ei ) noexcept { return handler_argument_traits::check(tup, ei) && check_arguments::check(tup, ei); } }; } //////////////////////////////////////// namespace detail { template struct handler_matches_any_error: std::false_type { }; template class L> struct handler_matches_any_error>: std::true_type { }; template class L, class Car, class... Cdr> struct handler_matches_any_error> { constexpr static bool value = handler_argument_traits::always_available && handler_matches_any_error>::value; }; } //////////////////////////////////////// namespace detail { template BOOST_LEAF_CONSTEXPR inline bool check_handler_( Tup & tup, error_info const & ei, leaf_detail_mp11::mp_list ) noexcept { return check_arguments::check(tup, ei); } template ::value, class FReturnType = fn_return_type> struct handler_caller { template BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list ) { return std::forward(f)( handler_argument_traits::get(tup, ei)... ); } }; template