You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
4.3 KiB
104 lines
4.3 KiB
#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
|
|
}
|