#ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED #define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED /// Copyright (c) 2018-2021 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) #ifndef BOOST_LEAF_ENABLE_WARNINGS /// # if defined(_MSC_VER) /// # pragma warning(push,1) /// # elif defined(__clang__) /// # pragma clang system_header /// # elif (__GNUC__*100+__GNUC_MINOR__>301) /// # pragma GCC system_header /// # endif /// #endif /// #include #include #ifndef BOOST_LEAF_NO_EXCEPTIONS # include #endif namespace boost { namespace leaf { class 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( std::system_error const * se = dynamic_cast(ex) ) if( is_error_id(se->code()) ) return leaf_detail::make_error_id(se->code().value()); if( std::error_code const * ec = dynamic_cast(ex) ) if( is_error_id(*ec) ) return leaf_detail::make_error_id(ec->value()); 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; template void print( std::basic_ostream & os ) const { os << "Error ID = " << err_id_.value(); #ifndef BOOST_LEAF_NO_EXCEPTIONS if( ex_ ) { os << "\nException dynamic type: " << leaf_detail::demangle(typeid(*ex_).name()) << "\nstd::exception::what(): " << ex_->what(); } #endif } public: BOOST_LEAF_CONSTEXPR explicit error_info( error_id id ) noexcept: #ifndef BOOST_LEAF_NO_EXCEPTIONS ex_(0), #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::basic_ostream & operator<<( std::basic_ostream & os, error_info const & x ) { os << "leaf::error_info: "; x.print(os); return os << '\n'; } }; //////////////////////////////////////// #if BOOST_LEAF_DIAGNOSTICS class diagnostic_info: public error_info { leaf_detail::e_unexpected_count const * e_uc_; void const * tup_; void (*print_)( std::ostream &, void const * tup, int key_to_print ); protected: diagnostic_info( diagnostic_info const & ) noexcept = default; template BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, leaf_detail::e_unexpected_count const * e_uc, Tup const & tup ) noexcept: error_info(ei), e_uc_(e_uc), tup_(&tup), print_(&leaf_detail::tuple_for_each::value, Tup>::print) { } public: template friend std::basic_ostream & operator<<( std::basic_ostream & os, diagnostic_info const & x ) { os << "leaf::diagnostic_info for "; x.print(os); os << ":\n"; x.print_(os, x.tup_, x.error().value()); if( x.e_uc_ ) x.e_uc_->print(os); return os; } }; namespace leaf_detail { struct diagnostic_info_: diagnostic_info { template BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, leaf_detail::e_unexpected_count const * e_uc, Tup const & tup ) noexcept: diagnostic_info(ei, e_uc, 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, handler_argument_traits_defaults::check(tup, 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) { } public: template friend std::basic_ostream & operator<<( std::basic_ostream & os, diagnostic_info const & x ) { os << "leaf::diagnostic_info requires #define BOOST_LEAF_DIAGNOSTICS 1\n" "leaf::error_info: "; x.print(os); return os << '\n'; } }; 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 & tup, error_info const & ei ) noexcept { return diagnostic_info_(ei); } }; } #endif //////////////////////////////////////// #if BOOST_LEAF_DIAGNOSTICS class verbose_diagnostic_info: public error_info { leaf_detail::e_unexpected_info const * e_ui_; void const * tup_; void (*print_)( std::ostream &, void const * tup, int key_to_print ); protected: verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, leaf_detail::e_unexpected_info const * e_ui, Tup const & tup ) noexcept: error_info(ei), e_ui_(e_ui), tup_(&tup), print_(&leaf_detail::tuple_for_each::value, Tup>::print) { } public: template friend std::basic_ostream & operator<<( std::basic_ostream & os, verbose_diagnostic_info const & x ) { os << "leaf::verbose_diagnostic_info for "; x.print(os); os << ":\n"; x.print_(os, x.tup_, x.error().value()); if( x.e_ui_ ) x.e_ui_->print(os); return os; } }; namespace leaf_detail { struct verbose_diagnostic_info_: verbose_diagnostic_info { template BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, leaf_detail::e_unexpected_info const * e_ui, Tup const & tup ) noexcept: verbose_diagnostic_info(ei, e_ui, 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, handler_argument_traits_defaults::check(tup, ei), tup); } }; } #else class verbose_diagnostic_info: public error_info { protected: verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei ) noexcept: error_info(ei) { } public: template friend std::basic_ostream & operator<<( std::basic_ostream & os, verbose_diagnostic_info const & x ) { os << "leaf::verbose_diagnostic_info requires #define BOOST_LEAF_DIAGNOSTICS 1\n" "leaf::error_info: "; x.print(os); return os << '\n'; } }; 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 & tup, 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(); } }; 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 0; } }; 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 0; } }; 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 0; } }; #endif 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 = std::get,SlotsTuple>::value>(tup).has_value(err.value()) ) return e; #ifndef BOOST_LEAF_NO_EXCEPTIONS else return peek_exception::peek(ei); #endif return 0; } template BOOST_LEAF_CONSTEXPR inline E * peek( SlotsTuple & tup, error_info const & ei ) noexcept { if( error_id err = ei.error() ) if( E * e = std::get,SlotsTuple>::value>(tup).has_value(err.value()) ) return e; #ifndef BOOST_LEAF_NO_EXCEPTIONS else return peek_exception::peek(ei); #endif return 0; } } //////////////////////////////////////// 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