16#ifndef CPPINTEROP_ERROR_H
17#define CPPINTEROP_ERROR_H
34enum class Status : uint8_t {
44enum class DiagnosticSeverity : uint8_t { Note, Warning, Error, Fatal };
48template <
typename T>
struct ArrayView {
49 const T* Data =
nullptr;
52 [[nodiscard]]
const T* begin()
const {
return Data; }
53 [[nodiscard]]
const T* end()
const {
return Data + Size; }
54 [[nodiscard]]
size_t size()
const {
return Size; }
55 [[nodiscard]]
bool empty()
const {
return Size == 0; }
56 const T& operator[](
size_t I)
const {
return Data[I]; }
62 const void* data =
nullptr;
64 [[nodiscard]]
bool isNull()
const {
return data ==
nullptr; }
96 [[nodiscard]]
bool isOk()
const {
return bits == 0; }
97 [[nodiscard]]
bool isInline()
const {
return (bits & 1U) == 1U; }
98 [[nodiscard]]
bool isSlice()
const {
return bits != 0 && (bits & 1U) == 0u; }
102 static ErrorRef makeInline(Status S) {
105 return ErrorRef{(
static_cast<uintptr_t
>(S) << 1) | 1U};
110 [[nodiscard]] Status inlineStatus()
const {
111 return static_cast<Status
>(bits >> 1);
116 static ErrorRef makeSlice(
const ErrorSlice* S) {
117 return ErrorRef{
reinterpret_cast<uintptr_t
>(S)};
119 [[nodiscard]]
const ErrorSlice* slice()
const {
120 return isSlice() ?
reinterpret_cast<const ErrorSlice*
>(bits) : nullptr;
146struct DiagnosticInfo {
147 DiagnosticSeverity Severity = DiagnosticSeverity::Error;
156 Status Code = Status::Ok;
157 std::vector<DiagnosticInfo> Diagnostics;
160 const char* Producer =
nullptr;
161 const char* ProducerSignature =
nullptr;
169class [[nodiscard]] CapturedError {
173 CapturedError() =
default;
174 explicit CapturedError(ErrorRef E) : Ref(E) {
RetainErrorRef(Ref); }
176 CapturedError(
const CapturedError& O) : Ref(O.Ref) {
RetainErrorRef(Ref); }
177 CapturedError(CapturedError&& O) noexcept : Ref(O.Ref) { O.Ref = ErrorRef{}; }
179 CapturedError& operator=(
const CapturedError& O) {
187 CapturedError& operator=(CapturedError&& O)
noexcept {
198 [[nodiscard]]
bool ok()
const {
return Ref.isOk(); }
199 explicit operator bool()
const {
return ok(); }
200 [[nodiscard]] Status status()
const {
return Ref.status(); }
201 [[nodiscard]] ErrorRef ref()
const {
return Ref; }
203 [[nodiscard]] ArrayView<DiagnosticRef> diagnostics()
const {
204 return Ref.diagnostics();
206 [[nodiscard]]
const char* producer()
const {
return Ref.producer(); }
207 [[nodiscard]]
const char* producerSignature()
const {
208 return Ref.producerSignature();
210 [[nodiscard]] ErrorRecord record()
const {
return Ref.record(); }
220template <
typename T>
class [[nodiscard]] Result {
221 static_assert(!std::is_same<T, void>::value,
222 "Result<void> is provided via specialization below");
224 static constexpr size_t kStorageSize =
sizeof(T) >
sizeof(ErrorRef)
227 static constexpr size_t kStorageAlign =
alignof(T) >
alignof(ErrorRef)
232 alignas(kStorageAlign)
unsigned char m_ValueBytes[kStorageSize];
235 bool m_HasError =
false;
238 mutable bool m_Unchecked =
true;
239 void markChecked()
const { m_Unchecked =
false; }
241 void markChecked()
const {}
244 T* valuePtr() {
return reinterpret_cast<T*
>(m_ValueBytes); }
245 const T* valuePtr()
const {
return reinterpret_cast<const T*
>(m_ValueBytes); }
248 Result() {
new (m_ValueBytes) T(); }
250 Result(T V) {
new (m_ValueBytes) T(std::move(V)); }
252 Result(ErrorRef E) : m_ErrState(E), m_HasError(!E.isOk()) {
257 Result(
const Result& Other) : m_HasError(Other.m_HasError) {
259 m_ErrState = Other.m_ErrState;
262 new (m_ValueBytes) T(*Other.valuePtr());
265 m_Unchecked = Other.m_Unchecked;
266 Other.m_Unchecked =
false;
270 Result(Result&& Other) noexcept : m_HasError(Other.m_HasError) {
272 m_ErrState = Other.m_ErrState;
273 Other.m_ErrState = ErrorRef{};
274 Other.m_HasError =
false;
276 new (m_ValueBytes) T(std::move(*Other.valuePtr()));
279 m_Unchecked = Other.m_Unchecked;
280 Other.m_Unchecked =
false;
286 if (m_Unchecked && m_HasError)
295 Result& operator=(
const Result&) =
delete;
296 Result& operator=(Result&&) =
delete;
298 void ignore()
const { markChecked(); }
300 [[nodiscard]]
bool ok()
const {
304 explicit operator bool()
const {
return ok(); }
306 [[nodiscard]] Status status()
const {
308 return m_HasError ? m_ErrState.status() : Status::Ok;
311 [[nodiscard]] ErrorRef error()
const {
313 return m_HasError ? m_ErrState : ErrorRef{};
319 [[nodiscard]] CapturedError share()
const {
321 return m_HasError ? CapturedError(m_ErrState) : CapturedError();
331 T value_or(T fallback)
const {
333 return m_HasError ? std::move(fallback) : *valuePtr();
339template <>
class [[nodiscard]] Result<void> {
342 mutable bool m_Unchecked =
true;
343 void markChecked()
const { m_Unchecked =
false; }
345 void markChecked()
const {}
350 Result(ErrorRef E) : m_ErrState(E) {
355 Result(
const Result& O) : m_ErrState(O.m_ErrState) {
356 if (!m_ErrState.isOk())
359 m_Unchecked = O.m_Unchecked;
360 O.m_Unchecked =
false;
364 Result(Result&& O) noexcept : m_ErrState(O.m_ErrState) {
366 m_Unchecked = O.m_Unchecked;
367 O.m_Unchecked =
false;
369 O.m_ErrState = ErrorRef{};
374 if (m_Unchecked && !m_ErrState.isOk())
377 if (!m_ErrState.isOk())
381 Result& operator=(
const Result&) =
delete;
382 Result& operator=(Result&&) =
delete;
384 void ignore()
const { markChecked(); }
386 [[nodiscard]]
bool ok()
const {
388 return m_ErrState.isOk();
390 explicit operator bool()
const {
return ok(); }
392 [[nodiscard]] Status status()
const {
394 return m_ErrState.status();
397 [[nodiscard]] ErrorRef error()
const {
402 [[nodiscard]] CapturedError share()
const {
404 return CapturedError(m_ErrState);
void RetainErrorRef(ErrorRef E)
Status GetStatus(ErrorRef E)
const char * GetDiagnosticFile(DiagnosticRef D)
void ResultAbort_UncheckedOnDtor(const ErrorRef &)
unsigned GetDiagnosticLine(DiagnosticRef D)
DiagnosticSeverity GetDiagnosticSeverity(DiagnosticRef D)
ArrayView< DiagnosticRef > GetDiagnostics(ErrorRef E)
const char * GetDiagnosticMessage(DiagnosticRef D)
void ReleaseErrorRef(ErrorRef E)
void ResultAbort_ValueOnError(const ErrorRef &)
unsigned GetDiagnosticColumn(DiagnosticRef D)