#ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED #define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED // Copyright 2018-2023 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 namespace boost { namespace leaf { template class BOOST_LEAF_SYMBOL_VISIBLE result; //////////////////////////////////////// class BOOST_LEAF_SYMBOL_VISIBLE error_info { error_info & operator=( error_info const & ) = delete; #ifndef BOOST_LEAF_NO_EXCEPTIONS static error_id unpack_error_id( std::exception const * ex ) noexcept { if( error_id const * err_id = dynamic_cast(ex) ) return *err_id; return current_error(); } std::exception * const ex_; #endif error_id const err_id_; protected: error_info( error_info const & ) noexcept = default; public: BOOST_LEAF_CONSTEXPR explicit error_info( error_id id ) noexcept: #ifndef BOOST_LEAF_NO_EXCEPTIONS ex_(nullptr), #endif err_id_(id) { } #ifndef BOOST_LEAF_NO_EXCEPTIONS explicit error_info( std::exception * ex ) noexcept: ex_(ex), err_id_(unpack_error_id(ex_)) { } #endif 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 } template friend std::ostream & operator<<( std::basic_ostream & os, error_info const & x ) { os << "Error ID: " << x.err_id_.value(); #ifndef BOOST_LEAF_NO_EXCEPTIONS if( x.ex_ ) { os << "\nException dynamic type: " << leaf_detail::demangle(typeid(*x.ex_).name()) << "\nstd::exception::what(): " << x.ex_->what(); } #endif return os << '\n'; } }; namespace leaf_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; } }; } //////////////////////////////////////// #if BOOST_LEAF_CFG_DIAGNOSTICS class diagnostic_info: public error_info { void const * tup_; void (*print_context_content_)( std::ostream &, void const * tup, int err_id_to_print ); protected: diagnostic_info( diagnostic_info const & ) noexcept = default; template BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, Tup const & tup ) noexcept: error_info(ei), tup_(&tup), print_context_content_(&leaf_detail::tuple_for_each::value, Tup>::print) { } template friend std::ostream & operator<<( std::basic_ostream & os, diagnostic_info const & x ) { os << static_cast(x); x.print_context_content_(os, x.tup_, x.error().value()); return os; } }; namespace leaf_detail { struct diagnostic_info_: diagnostic_info { template BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, Tup const & tup ) noexcept: diagnostic_info(ei, tup) { } }; template <> struct handler_argument_traits: handler_argument_always_available { template BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept { return diagnostic_info_(ei, tup); } }; } #else class diagnostic_info: public error_info { protected: diagnostic_info( diagnostic_info const & ) noexcept = default; BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei ) noexcept: error_info(ei) { } template friend std::ostream & operator<<( std::basic_ostream & os, diagnostic_info const & x ) { return os << "diagnostic_info not available due to BOOST_LEAF_CFG_DIAGNOSTICS=0. Basic error_info follows.\n" << static_cast(x); } }; namespace leaf_detail { struct diagnostic_info_: diagnostic_info { BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei ) noexcept: diagnostic_info(ei) { } }; template <> struct handler_argument_traits: handler_argument_always_available { template BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const &, error_info const & ei ) noexcept { return diagnostic_info_(ei); } }; } #endif //////////////////////////////////////// #if BOOST_LEAF_CFG_DIAGNOSTICS #if BOOST_LEAF_CFG_CAPTURE class verbose_diagnostic_info: public diagnostic_info { leaf_detail::dynamic_allocator const * const da_; protected: verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, Tup const & tup, leaf_detail::dynamic_allocator const * da ) noexcept: diagnostic_info(ei, tup), da_(da) { } template friend std::ostream & operator<<( std::basic_ostream & os, verbose_diagnostic_info const & x ) { os << static_cast(x); if( x.da_ ) x.da_->print(os, "Unhandled error objects:\n", x.error().value()); return os; } }; namespace leaf_detail { struct verbose_diagnostic_info_: verbose_diagnostic_info { template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, Tup const & tup, dynamic_allocator const * da ) noexcept: verbose_diagnostic_info(ei, tup, da) { } }; template <> struct handler_argument_traits: handler_argument_always_available { template BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept { return verbose_diagnostic_info_(ei, tup, handler_argument_traits_defaults::check(tup, ei)); } }; } #else class verbose_diagnostic_info: public diagnostic_info { protected: verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, Tup const & tup ) noexcept: diagnostic_info(ei, tup) { } template friend std::ostream & operator<<( std::basic_ostream & os, verbose_diagnostic_info const & x ) { return os << "verbose_diagnostic_info not available due to BOOST_LEAF_CFG_CAPTURE=0. Basic diagnostic_info follows.\n" << static_cast(x); } }; namespace leaf_detail { struct verbose_diagnostic_info_: verbose_diagnostic_info { template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, Tup const & tup ) noexcept: verbose_diagnostic_info(ei, tup) { } }; template <> struct handler_argument_traits: handler_argument_always_available { template BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept { return verbose_diagnostic_info_(ei, tup); } }; } #endif #else class verbose_diagnostic_info: public diagnostic_info { protected: verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei ) noexcept: diagnostic_info(ei) { } template friend std::ostream & operator<<( std::basic_ostream & os, verbose_diagnostic_info const & x ) { return os << "verbose_diagnostic_info not available due to BOOST_LEAF_CFG_DIAGNOSTICS=0. Basic error_info follows.\n" << static_cast(x); } }; namespace leaf_detail { struct verbose_diagnostic_info_: verbose_diagnostic_info { BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei ) noexcept: verbose_diagnostic_info(ei) { } }; template <> struct handler_argument_traits: handler_argument_always_available { template BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const &, error_info const & ei ) noexcept { return verbose_diagnostic_info_(ei); } }; } #endif //////////////////////////////////////// namespace leaf_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 leaf_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 leaf_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 leaf_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