# pragma once
# include <stdexcept>
# include <stacktrace>
# include <source_location>
# include "exopt.h"
# include "optional.h"
# include "either.h"
# include "util.hh"
# define _EO_DEFEXCEPT_BASIC_(NAME, BASE, ...) class NAME : public ::exopt:: BASE { \
constexpr static inline auto MESSSAGE = ( __VA_ARGS__ ) ; \
public : \
_EO_CLASS_DEFINE ( NAME , constexpr , noexcept , virtual , = default ) ; \
constexpr virtual std : : string_view message ( ) const noexcept override { return { MESSAGE } ; } \
}
# define _EO_DEFEXCEPT_BASIC(NAME, MSG) _EO_DEFEXCEPT_BASIC_(NAME, Error, MSG)
# define _EO_DEFEXCEPT_TRACE_BASIC(NAME, MSG) _EO_DEFEXCEPT_BASIC_(NAME, TracedError, MSG)
namespace exopt {
// Report generated from an error. (virtual base, not abstract.)
class Report {
public :
virtual ~ Report ( ) ;
} ;
// This is base thrown (base, abstract)
class Error {
public :
constexpr Error ( Error const & ) = default ;
constexpr Error ( Error & & ) = default ;
constexpr Error & operator = ( Error & & ) = default ;
constexpr Error & operator = ( Error const & ) = default ;
virtual types : : Box < TracedError > into_traced ( std : : stacktrace trace & & ) & & noexcept ; // = std::stacktrace::current()) && noexcept;
inline typed : : Box < TracedError > into_traced ( std : : stacktrace trace = std : : stacktrace : : current ( ) ) & & noexcept
{ return std : : move ( * this ) . into_traced ( std : : move ( trace ) ) ; }
constexpr virtual std : : source_location const & location ( ) const noexcept { return m_location ; }
constexpr operator std : : string_view ( ) const noexcept { return message ( ) ; }
constexpr virtual std : : string_view message ( ) const noexcept = 0 ;
//constexpr virtual types::Option<Error&> inner() noexcept { return { std::nullopt }; }
constexpr virtual types : : Option < Error const & > inner ( ) const noexcept { return { std : : nullopt } ; }
constexpr virtual types : : MaybeOwned < Report > into_report ( ) & noexcept { /* TODO */ } //TODO: Maybe just use `std::optional<std::reference_wrapper<Error>>`? Or Box<Report&>?
constexpr virtual types : : MaybeOwned < Report > into_report ( ) & & noexcept { /* TODO: auto{*this}.into_report() */ }
constexpr virtual ~ Error ( ) = default ;
protected :
constexpr Error ( std : : source_location loc = std : : source_location : : current ( ) ) noexcept
: m_location ( std : : move ( loc ) ) { }
private :
std : : source_location m_location ;
/ / Moved this to non - constexpr subclass ` TracedError ` \
std : : unique_ptr < std : : stacktrace > m_trace { nullptr } ; //TODO: Change to exopt::types::Box<> to make copy ctor/assign work
} ;
// This is propagated returned, along with a stack trace. (base, abstract)
class TracedError : public Error {
public :
TracedError ( TracedError const & ) = default ;
TracedError ( TracedError & & ) = default ;
TracedError & operator = ( TracedError & & ) = default ;
TracedError & operator = ( TracedError const & ) = default ;
virtual ~ TracedError ( ) = default ;
inline virtual std : : stacktrace const & stacktrace ( ) const noexcept { return m_trace ; }
protected :
inline TracedError (
std : : source_location loc = std : : source_location : : current ( )
, std : : stacktrace trace = std : : stacktrace : : current ( ) ) noexcept
: Error ( std : : move ( loc ) ) , m_trace ( std : : move ( trace ) ) { }
/*inline TracedError(
std : : stacktrace & & trace ,
, std : : source_location loc = std : : source_location : : current ( ) ) noexcept
: Error ( std : : move ( loc ) ) , m_trace ( std : : move ( trace ) ) { } */
inline TracedError (
std : : stacktrace & & trace ,
, std : : source_location & & loc ) noexcept
: Error ( std : : move ( loc ) ) , m_trace ( std : : move ( trace ) ) { }
private :
inline types : : Box < TracedError > into_traced ( std : : stacktrace trace & & ) & & noexcept override final // = std::stacktrace::current()) && noexcept;
{ return typed : : Box < TracedError > { std : : move ( * this ) } ; } //TODO: XXX: How to check if `this` is *already* boxed? This dynamic double-boxing is inefficient, but also can probably not be checked unless relying on enabling RTTI by default
inline typed : : Box < TracedError > into_traced ( std : : stacktrace trace = std : : stacktrace : : current ( ) ) & & noexcept override final
{ return typed : : Box < TracedError > { std : : move ( * this ) } ; }
std : : stacktrace m_trace ; //TODO: Maybe box this? idk how big it is...
} ;
#if 0
// This is thrown. (virtual base, abstract)
class Panic : /*virtual?? I think it should be XXX*/ Error {
//TODO: How to make a `constexpr` deduced panic that has stack-trace at runtime only? Is it needed? Hnm...
} ;
//TODO: Fatal(string) : public virtual Panic
# endif
}