mirror of
https://github.com/boostorg/leaf.git
synced 2026-02-22 03:22:25 +00:00
Improved diagnostic_details, able to access error objects from parent error handling scopes
This commit is contained in:
@@ -50,10 +50,10 @@ namespace detail
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static error_type * check( Tup &, error_info const & ) noexcept;
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static E get( Tup & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static E get( Context & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
return *check(tup, ei);
|
||||
return *check(ctx.tup(), ei);
|
||||
}
|
||||
|
||||
static_assert(!is_predicate<error_type>::value, "Handlers must take predicate arguments by value");
|
||||
@@ -75,10 +75,10 @@ namespace detail
|
||||
return e && Pred::evaluate(*e);
|
||||
}
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static Pred get( Tup const & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static Pred get( Context const & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
return Pred{*base::check(tup, ei)};
|
||||
return Pred{*base::check(ctx.tup(), ei)};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -119,10 +119,10 @@ namespace detail
|
||||
template <class E>
|
||||
struct handler_argument_traits<E *>: handler_argument_always_available<typename std::remove_const<E>::type>
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static E * get( Tup & tup, error_info const & ei) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static E * get( Context & ctx, error_info const & ei) noexcept
|
||||
{
|
||||
return handler_argument_traits_defaults<E>::check(tup, ei);
|
||||
return handler_argument_traits_defaults<E>::check(ctx.tup(), ei);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -204,7 +204,8 @@ namespace detail
|
||||
tuple_for_each<I-1,Tup>::unload(tup, err_id);
|
||||
}
|
||||
|
||||
static void serialize_to(encoder & e, void const * tup, error_id id)
|
||||
template <class Encoder>
|
||||
static void serialize_to(Encoder & e, void const * tup, error_id id)
|
||||
{
|
||||
BOOST_LEAF_ASSERT(tup != nullptr);
|
||||
tuple_for_each<I-1,Tup>::serialize_to(e, tup, id);
|
||||
@@ -221,10 +222,12 @@ namespace detail
|
||||
BOOST_LEAF_CONSTEXPR static void serialize_to(encoder &, void const *, error_id) { }
|
||||
};
|
||||
|
||||
template <class Tup>
|
||||
void serialize_tuple_contents_to(encoder & e, void const * tup, error_id id)
|
||||
class context_base;
|
||||
|
||||
template <class Context>
|
||||
void serialize_context_to(encoder & e, context_base const & ctx, error_id id)
|
||||
{
|
||||
tuple_for_each<std::tuple_size<Tup>::value, Tup>::serialize_to(e, tup, id);
|
||||
static_cast<Context const &>(ctx).serialize_to(e, id);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -265,8 +268,57 @@ namespace detail
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// The context_base type is able to walk up the parent error handling
|
||||
// scopes to collect relevant error objects, so they can be serialized or
|
||||
// printed by diagnostic_details.
|
||||
//
|
||||
// This introduces a bit of overhead which is semantically similar to the
|
||||
// rest of the overhead introduced by BOOST_LEAF_CFG_CAPTURE=1, namely
|
||||
// allocating unhandled error objects dynamically if diagnostic_details is
|
||||
// handled.
|
||||
class context_base
|
||||
{
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
context_base( context_base const & ) = delete;
|
||||
context_base & operator=( context_base const & ) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
context_base * parent_ = nullptr;
|
||||
|
||||
context_base()
|
||||
{
|
||||
tls::reserve_ptr<context_base>();
|
||||
}
|
||||
|
||||
context_base( context_base && ) noexcept = default;
|
||||
~context_base() noexcept = default;
|
||||
|
||||
void link() noexcept
|
||||
{
|
||||
parent_ = tls::read_ptr<context_base>();
|
||||
tls::write_ptr<context_base>(this);
|
||||
}
|
||||
|
||||
void unlink() noexcept
|
||||
{
|
||||
BOOST_LEAF_ASSERT(tls::read_ptr<context_base>() == this);
|
||||
tls::write_ptr<context_base>(parent_);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual void serialize_to_( encoder &, error_id ) const = 0;
|
||||
#endif
|
||||
}; // class context_base
|
||||
} // namespace detail
|
||||
|
||||
|
||||
template <class... E>
|
||||
class context
|
||||
class context final:
|
||||
public detail::context_base
|
||||
{
|
||||
context( context const & ) = delete;
|
||||
context & operator=( context const & ) = delete;
|
||||
@@ -305,9 +357,29 @@ class context
|
||||
}
|
||||
};
|
||||
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
void serialize_to_( detail::encoder & e, error_id id ) const override
|
||||
{
|
||||
detail::tuple_for_each<std::tuple_size<Tup>::value, Tup>::serialize_to(e, &tup_, id);
|
||||
if( parent_ )
|
||||
parent_->serialize_to_(e, id);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
template <class Encoder>
|
||||
void serialize_to( Encoder & e, error_id id ) const
|
||||
{
|
||||
detail::tuple_for_each<std::tuple_size<Tup>::value, Tup>::serialize_to(e, &tup_, id);
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
if( parent_ )
|
||||
parent_->serialize_to_(e, id);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR context( context && x ) noexcept:
|
||||
context_base(std::move(x)),
|
||||
tup_(std::move(x.tup_)),
|
||||
is_active_(false)
|
||||
{
|
||||
@@ -338,10 +410,13 @@ public:
|
||||
{
|
||||
using namespace detail;
|
||||
BOOST_LEAF_ASSERT(!is_active());
|
||||
tuple_for_each<std::tuple_size<Tup>::value,Tup>::activate(tup_);
|
||||
#if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
|
||||
thread_id_ = std::this_thread::get_id();
|
||||
#endif
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
context_base::link();
|
||||
#endif
|
||||
tuple_for_each<std::tuple_size<Tup>::value,Tup>::activate(tup_);
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
@@ -349,12 +424,15 @@ public:
|
||||
{
|
||||
using namespace detail;
|
||||
BOOST_LEAF_ASSERT(is_active());
|
||||
is_active_ = false;
|
||||
#if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
|
||||
BOOST_LEAF_ASSERT(std::this_thread::get_id() == thread_id_);
|
||||
thread_id_ = std::thread::id();
|
||||
#endif
|
||||
is_active_ = false;
|
||||
tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_);
|
||||
#if BOOST_LEAF_CFG_CAPTURE
|
||||
context_base::unlink();
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_LEAF_CONSTEXPR void unload(error_id id) noexcept(!BOOST_LEAF_CFG_CAPTURE)
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace detail
|
||||
friend class capture_list;
|
||||
|
||||
virtual void unload( int err_id ) = 0;
|
||||
virtual void serialize_to(encoder &, error_id const &) const = 0;
|
||||
virtual void serialize_to_(encoder &, error_id const &) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace detail
|
||||
for_each(
|
||||
[&e, &id]( node const & n )
|
||||
{
|
||||
n.serialize_to(e, id);
|
||||
n.serialize_to_(e, id);
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,18 @@ namespace boost { namespace leaf {
|
||||
|
||||
class diagnostic_info: public error_info
|
||||
{
|
||||
void const * tup_;
|
||||
void (*serialize_tuple_contents_to_)(detail::encoder &, void const *, error_id);
|
||||
detail::context_base const & ctx_;
|
||||
void (*serialize_ctx_to_)(detail::encoder &, detail::context_base const &, error_id);
|
||||
|
||||
protected:
|
||||
|
||||
diagnostic_info( diagnostic_info const & ) noexcept = default;
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, Tup const & tup ) noexcept:
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, Context const & ctx ) noexcept:
|
||||
error_info(ei),
|
||||
tup_(&tup),
|
||||
serialize_tuple_contents_to_(&detail::serialize_tuple_contents_to<Tup>)
|
||||
ctx_(ctx),
|
||||
serialize_ctx_to_(&detail::serialize_context_to<Context>)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ protected:
|
||||
void serialize_to_(Encoder & e) const
|
||||
{
|
||||
static_assert(std::is_base_of<detail::encoder, Encoder>::value, "Encoder must derive from detail::encoder");
|
||||
serialize_tuple_contents_to_(e, tup_, error());
|
||||
serialize_ctx_to_(e, ctx_, error());
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -61,9 +61,9 @@ namespace detail
|
||||
{
|
||||
struct diagnostic_info_: diagnostic_info
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, Tup const & tup ) noexcept:
|
||||
diagnostic_info(ei, tup)
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, Context const & ctx ) noexcept:
|
||||
diagnostic_info(ei, ctx)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -71,10 +71,10 @@ namespace detail
|
||||
template <>
|
||||
struct handler_argument_traits<diagnostic_info const &>: handler_argument_always_available<e_source_location>
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Context const & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
return diagnostic_info_(ei, tup);
|
||||
return diagnostic_info_(ei, ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -91,9 +91,9 @@ protected:
|
||||
|
||||
diagnostic_details( diagnostic_details const & ) noexcept = default;
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details( error_info const & ei, Tup const & tup, detail::dynamic_allocator const * da ) noexcept:
|
||||
diagnostic_info(ei, tup),
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details( error_info const & ei, Context const & ctx, detail::dynamic_allocator const * da ) noexcept:
|
||||
diagnostic_info(ei, ctx),
|
||||
da_(da)
|
||||
{
|
||||
}
|
||||
@@ -136,9 +136,9 @@ namespace detail
|
||||
{
|
||||
struct diagnostic_details_: diagnostic_details
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details_( error_info const & ei, Tup const & tup, dynamic_allocator const * da ) noexcept:
|
||||
diagnostic_details(ei, tup, da)
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details_( error_info const & ei, Context const & ctx, dynamic_allocator const * da ) noexcept:
|
||||
diagnostic_details(ei, ctx, da)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -146,11 +146,11 @@ namespace detail
|
||||
template <>
|
||||
struct handler_argument_traits<diagnostic_details const &>: handler_argument_always_available<e_source_location, dynamic_allocator>
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Tup const & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Context const & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
slot<dynamic_allocator> const * da = find_in_tuple<slot<dynamic_allocator>>(tup);
|
||||
return diagnostic_details_(ei, tup, da ? &da->get() : nullptr );
|
||||
slot<dynamic_allocator> const * da = find_in_tuple<slot<dynamic_allocator>>(ctx.tup());
|
||||
return diagnostic_details_(ei, ctx, da ? &da->get() : nullptr );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -163,9 +163,9 @@ protected:
|
||||
|
||||
diagnostic_details( diagnostic_details const & ) noexcept = default;
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details( error_info const & ei, Tup const & tup ) noexcept:
|
||||
diagnostic_info(ei, tup)
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details( error_info const & ei, Context const & ctx ) noexcept:
|
||||
diagnostic_info(ei, ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -197,9 +197,9 @@ namespace detail
|
||||
{
|
||||
struct diagnostic_details_: diagnostic_details
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details_( error_info const & ei, Tup const & tup ) noexcept:
|
||||
diagnostic_details(ei, tup)
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR diagnostic_details_( error_info const & ei, Context const & ctx ) noexcept:
|
||||
diagnostic_details(ei, ctx)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -207,10 +207,10 @@ namespace detail
|
||||
template <>
|
||||
struct handler_argument_traits<diagnostic_details const &>: handler_argument_always_available<e_source_location>
|
||||
{
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Tup const & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Context const & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
return diagnostic_details_(ei, tup);
|
||||
return diagnostic_details_(ei, ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace detail
|
||||
{
|
||||
impl::unload(err_id);
|
||||
}
|
||||
void serialize_to(encoder & e, error_id const & id) const override
|
||||
void serialize_to_(encoder & e, error_id const & id) const override
|
||||
{
|
||||
impl::serialize_to(e, id);
|
||||
}
|
||||
@@ -305,7 +305,7 @@ namespace detail
|
||||
{
|
||||
std::rethrow_exception(ex_);
|
||||
}
|
||||
void serialize_to(encoder &, error_id const &) const override
|
||||
void serialize_to_(encoder &, error_id const &) const override
|
||||
{
|
||||
}
|
||||
std::exception_ptr const ex_;
|
||||
|
||||
@@ -377,10 +377,10 @@ namespace detail
|
||||
template <class R, class F, bool IsResult = is_result_type<R>::value, class FReturnType = fn_return_type<F>>
|
||||
struct handler_caller
|
||||
{
|
||||
template <class Tup, class... A>
|
||||
BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
|
||||
template <class Context, class... A>
|
||||
BOOST_LEAF_CONSTEXPR static R call( Context & ctx, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
|
||||
{
|
||||
return std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... );
|
||||
return std::forward<F>(f)( handler_argument_traits<A>::get(ctx, ei)... );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -389,10 +389,10 @@ namespace detail
|
||||
{
|
||||
using R = Result<void, E...>;
|
||||
|
||||
template <class Tup, class... A>
|
||||
BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
|
||||
template <class Context, class... A>
|
||||
BOOST_LEAF_CONSTEXPR static R call( Context & ctx, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
|
||||
{
|
||||
std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... );
|
||||
std::forward<F>(f)( handler_argument_traits<A>::get(ctx, ei)... );
|
||||
return { };
|
||||
}
|
||||
};
|
||||
@@ -406,61 +406,61 @@ namespace detail
|
||||
template <class... T>
|
||||
struct is_tuple<std::tuple<T...> &>: std::true_type { };
|
||||
|
||||
template <class R, class Tup, class H>
|
||||
template <class R, class Context, class H>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
typename std::enable_if<!is_tuple<typename std::decay<H>::type>::value, R>::type
|
||||
handle_error_( Tup & tup, error_info const & ei, H && h )
|
||||
handle_error_( Context & ctx, error_info const & ei, H && h )
|
||||
{
|
||||
static_assert( handler_matches_any_error<fn_mp_args<H>>::value, "The last handler passed to handle_all must match any error." );
|
||||
return handler_caller<R, H>::call( tup, ei, std::forward<H>(h), fn_mp_args<H>{ } );
|
||||
return handler_caller<R, H>::call( ctx, ei, std::forward<H>(h), fn_mp_args<H>{ } );
|
||||
}
|
||||
|
||||
template <class R, class Tup, class Car, class... Cdr>
|
||||
template <class R, class Context, class Car, class... Cdr>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
typename std::enable_if<!is_tuple<typename std::decay<Car>::type>::value, R>::type
|
||||
handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr )
|
||||
handle_error_( Context & ctx, error_info const & ei, Car && car, Cdr && ... cdr )
|
||||
{
|
||||
if( handler_matches_any_error<fn_mp_args<Car>>::value || check_handler_( tup, ei, fn_mp_args<Car>{ } ) )
|
||||
return handler_caller<R, Car>::call( tup, ei, std::forward<Car>(car), fn_mp_args<Car>{ } );
|
||||
if( handler_matches_any_error<fn_mp_args<Car>>::value || check_handler_( ctx.tup(), ei, fn_mp_args<Car>{ } ) )
|
||||
return handler_caller<R, Car>::call( ctx, ei, std::forward<Car>(car), fn_mp_args<Car>{ } );
|
||||
else
|
||||
return handle_error_<R>( tup, ei, std::forward<Cdr>(cdr)...);
|
||||
return handle_error_<R>( ctx, ei, std::forward<Cdr>(cdr)...);
|
||||
}
|
||||
|
||||
template <class R, class Tup, class HTup, size_t ... I>
|
||||
template <class R, class Context, class HTup, size_t ... I>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
R
|
||||
handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup )
|
||||
handle_error_tuple_( Context & ctx, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup )
|
||||
{
|
||||
return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))...);
|
||||
return handle_error_<R>(ctx, ei, std::get<I>(std::forward<HTup>(htup))...);
|
||||
}
|
||||
|
||||
template <class R, class Tup, class HTup, class... Cdr, size_t ... I>
|
||||
template <class R, class Context, class HTup, class... Cdr, size_t ... I>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
R
|
||||
handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup, Cdr && ... cdr )
|
||||
handle_error_tuple_( Context & ctx, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup, Cdr && ... cdr )
|
||||
{
|
||||
return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))..., std::forward<Cdr>(cdr)...);
|
||||
return handle_error_<R>(ctx, ei, std::get<I>(std::forward<HTup>(htup))..., std::forward<Cdr>(cdr)...);
|
||||
}
|
||||
|
||||
template <class R, class Tup, class H>
|
||||
template <class R, class Context, class H>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
typename std::enable_if<is_tuple<typename std::decay<H>::type>::value, R>::type
|
||||
handle_error_( Tup & tup, error_info const & ei, H && h )
|
||||
handle_error_( Context & ctx, error_info const & ei, H && h )
|
||||
{
|
||||
return handle_error_tuple_<R>(
|
||||
tup,
|
||||
ctx,
|
||||
ei,
|
||||
leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<H>::type>::value>(),
|
||||
std::forward<H>(h));
|
||||
}
|
||||
|
||||
template <class R, class Tup, class Car, class... Cdr>
|
||||
template <class R, class Context, class Car, class... Cdr>
|
||||
BOOST_LEAF_CONSTEXPR inline
|
||||
typename std::enable_if<is_tuple<typename std::decay<Car>::type>::value, R>::type
|
||||
handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr )
|
||||
handle_error_( Context & ctx, error_info const & ei, Car && car, Cdr && ... cdr )
|
||||
{
|
||||
return handle_error_tuple_<R>(
|
||||
tup,
|
||||
ctx,
|
||||
ei,
|
||||
leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<Car>::type>::value>(),
|
||||
std::forward<Car>(car),
|
||||
@@ -478,7 +478,7 @@ context<E...>::
|
||||
handle_error( error_id id, H && ... h ) const
|
||||
{
|
||||
BOOST_LEAF_ASSERT(!is_active());
|
||||
return detail::handle_error_<R>(tup(), error_info(id, nullptr, this->get<e_source_location>(id)), std::forward<H>(h)...);
|
||||
return detail::handle_error_<R>(*this, error_info(id, nullptr, this->get<e_source_location>(id)), std::forward<H>(h)...);
|
||||
}
|
||||
|
||||
template <class... E>
|
||||
@@ -489,7 +489,7 @@ context<E...>::
|
||||
handle_error( error_id id, H && ... h )
|
||||
{
|
||||
BOOST_LEAF_ASSERT(!is_active());
|
||||
return detail::handle_error_<R>(tup(), error_info(id, nullptr, this->get<e_source_location>(id)), std::forward<H>(h)...);
|
||||
return detail::handle_error_<R>(*this, error_info(id, nullptr, this->get<e_source_location>(id)), std::forward<H>(h)...);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
@@ -585,7 +585,7 @@ namespace detail
|
||||
{
|
||||
ctx.deactivate();
|
||||
error_id id = detail::unpack_error_id(ex);
|
||||
return handle_error_<R>(ctx.tup(), error_info(id, &ex, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
return handle_error_<R>(ctx, error_info(id, &ex, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
[&]() -> R
|
||||
{
|
||||
ctx.unload(id);
|
||||
@@ -596,7 +596,7 @@ namespace detail
|
||||
{
|
||||
ctx.deactivate();
|
||||
error_id id = current_error();
|
||||
return handle_error_<R>(ctx.tup(), error_info(id, nullptr, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
return handle_error_<R>(ctx, error_info(id, nullptr, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
[&]() -> R
|
||||
{
|
||||
ctx.unload(id);
|
||||
@@ -675,7 +675,7 @@ try_catch( TryBlock && try_block, H && ... h )
|
||||
{
|
||||
ctx.deactivate();
|
||||
error_id id = detail::unpack_error_id(ex);
|
||||
return detail::handle_error_<R>(ctx.tup(), error_info(id, &ex, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
return detail::handle_error_<R>(ctx, error_info(id, &ex, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
[&]() -> R
|
||||
{
|
||||
ctx.unload(id);
|
||||
@@ -686,7 +686,7 @@ try_catch( TryBlock && try_block, H && ... h )
|
||||
{
|
||||
ctx.deactivate();
|
||||
error_id id = current_error();
|
||||
return detail::handle_error_<R>(ctx.tup(), error_info(id, nullptr, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
return detail::handle_error_<R>(ctx, error_info(id, nullptr, ctx.template get<e_source_location>(id)), std::forward<H>(h)...,
|
||||
[&]() -> R
|
||||
{
|
||||
ctx.unload(id);
|
||||
@@ -863,10 +863,10 @@ namespace detail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class Tup>
|
||||
BOOST_LEAF_CONSTEXPR static boost::error_info<Tag, T> get( Tup const & tup, error_info const & ei ) noexcept
|
||||
template <class Context>
|
||||
BOOST_LEAF_CONSTEXPR static boost::error_info<Tag, T> get( Context const & ctx, error_info const & ei ) noexcept
|
||||
{
|
||||
return boost::error_info<Tag, T>(*check(tup, ei));
|
||||
return boost::error_info<Tag, T>(*check(ctx.tup(), ei));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -427,6 +427,47 @@ int main()
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::try_handle_some(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::new_error(my_error<1>{1, "error one"});
|
||||
},
|
||||
[](leaf::diagnostic_details const & dd) -> leaf::result<int>
|
||||
{
|
||||
boost::json::value j;
|
||||
output_encoder e{j};
|
||||
dd.serialize_to(e);
|
||||
std::cout << __LINE__ << " nested diagnostic_details JSON output:\n" << boost::json::serialize(j) << std::endl;
|
||||
if( BOOST_LEAF_CFG_CAPTURE )
|
||||
{
|
||||
BOOST_TEST(j.as_object().contains("my_error<1>"));
|
||||
if( j.as_object().contains("my_error<1>") )
|
||||
{
|
||||
auto const & e1j = j.at("my_error<1>");
|
||||
BOOST_TEST_EQ(boost::json::value_to<int>(e1j.at("code")), 1);
|
||||
BOOST_TEST_EQ(boost::json::value_to<std::string>(e1j.at("message")), "error one");
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_TEST(j.as_object().find("my_error<1>") == j.as_object().end());
|
||||
return dd.error();
|
||||
} );
|
||||
},
|
||||
[](my_error<1> const &)
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,24 @@ enum class my_error_code
|
||||
error3
|
||||
};
|
||||
|
||||
class my_error_code_category: public std::error_category
|
||||
{
|
||||
public:
|
||||
char const * name() const noexcept override { return "my_error_code"; }
|
||||
std::string message(int) const override { return "my_error_code"; }
|
||||
};
|
||||
|
||||
my_error_code_category const & get_my_error_code_category()
|
||||
{
|
||||
static my_error_code_category cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
std::error_code make_error_code(my_error_code e)
|
||||
{
|
||||
return std::error_code(static_cast<int>(e), get_my_error_code_category());
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct is_error_code_enum<my_error_code>: std::true_type { };
|
||||
|
||||
@@ -128,5 +128,43 @@ int main()
|
||||
BOOST_TEST_EQ(counter, 0);
|
||||
} );
|
||||
|
||||
BOOST_TEST_EQ(counter, 0);
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::try_handle_some(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::new_error(info<1>{});
|
||||
},
|
||||
[]( leaf::diagnostic_details const & di ) -> leaf::result<int>
|
||||
{
|
||||
#if BOOST_LEAF_CFG_STD_STRING
|
||||
std::ostringstream st;
|
||||
st << di;
|
||||
std::string s = st.str();
|
||||
std::cout << s << std::endl;
|
||||
if( BOOST_LEAF_CFG_DIAGNOSTICS )
|
||||
if( BOOST_LEAF_CFG_CAPTURE )
|
||||
BOOST_TEST_NE(s.find("info<1>"), s.npos);
|
||||
else
|
||||
BOOST_TEST_EQ(s.find("info<1>"), s.npos);
|
||||
#endif
|
||||
return di.error();
|
||||
} );
|
||||
},
|
||||
[]( info<1> const & )
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
BOOST_TEST_EQ(counter, 0);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -428,6 +428,47 @@ int main()
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int r = leaf::try_handle_all(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::try_handle_some(
|
||||
[]() -> leaf::result<int>
|
||||
{
|
||||
return leaf::new_error(my_error<1>{1, "error one"});
|
||||
},
|
||||
[](leaf::diagnostic_details const & dd) -> leaf::result<int>
|
||||
{
|
||||
nlohmann::ordered_json j;
|
||||
output_encoder e{j};
|
||||
dd.serialize_to(e);
|
||||
std::cout << __LINE__ << " nested diagnostic_details JSON output:\n" << std::setw(2) << j << std::endl;
|
||||
if( BOOST_LEAF_CFG_CAPTURE )
|
||||
{
|
||||
BOOST_TEST(j.contains("my_error<1>"));
|
||||
if( j.contains("my_error<1>") )
|
||||
{
|
||||
auto const & e1j = j["my_error<1>"];
|
||||
BOOST_TEST_EQ(e1j["code"].get<int>(), 1);
|
||||
BOOST_TEST_EQ(e1j["message"].get<std::string>(), "error one");
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_TEST(!j.contains("my_error<1>"));
|
||||
return dd.error();
|
||||
} );
|
||||
},
|
||||
[](my_error<1> const &)
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
[]
|
||||
{
|
||||
return 2;
|
||||
} );
|
||||
BOOST_TEST_EQ(r, 1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user