Luna/luna/include/luna/Result.h
apio 00cf267ac7
All checks were successful
continuous-integration/drone/push Build is passing
Lock EFIXME and error_string() behind a #define
2022-12-18 18:14:48 +01:00

205 lines
4.7 KiB
C++

#pragma once
#define _LUNA_SYSTEM_ERROR_EXTENSIONS
#include <luna/Check.h>
#include <luna/Move.h>
#include <luna/Option.h>
#include <luna/PlacementNew.h>
#include <luna/SystemError.h>
#include <luna/Types.h>
struct Error
{
Error(int err)
{
error = err;
}
int error;
};
template <typename T> class Result
{
public:
Result(const T& value) : m_value(value), m_has_value(true)
{
}
Result(T&& value) : m_value(move(value)), m_has_value(true)
{
}
Result(const Result<T>& other) : m_value(other.m_value), m_has_value(other.m_has_value), m_error(other.m_error)
{
}
Result(Result<T>&& other) : m_value(move(other.m_value)), m_has_value(other.m_has_value), m_error(other.m_error)
{
other.m_has_value = false;
}
Result(const Error& err) : m_value(), m_has_value(false), m_error(err.error)
{
}
bool has_error() const
{
return !m_has_value;
}
bool has_value() const
{
return m_has_value;
}
int error() const
{
expect(has_error(), "Result::error() called on a Result that holds a value");
return m_error;
}
Error release_error() const
{
expect(has_error(), "Result::release_error() called on a Result that holds a value");
return {m_error};
}
const char* error_string() const
{
expect(has_error(), "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error);
}
T value() const
{
expect(has_value(), "Result::value() called on a Result that holds an error");
return m_value.value();
}
T expect_value(const char* reason) const
{
expect(has_value(), reason);
return m_value.value();
}
T value_or(const T& other) const
{
return m_value.value_or(other);
}
bool try_set_value(T& ref) const
{
return m_value.try_set_value(ref);
}
Result<bool> try_set_value_with_specific_error(T& ref, int error)
{
if (has_error() && m_error != error) return release_error();
return m_value.try_set_value(ref);
}
T release_value()
{
expect(has_value(), "Result::release_value() called on a Result that holds an error");
return m_value.release_value();
}
T expect_release_value(const char* reason)
{
expect(has_value(), reason);
return m_value.release_value();
}
private:
Option<T> m_value;
bool m_has_value;
int m_error;
};
template <> class Result<void>
{
public:
Result() : m_has_error(false)
{
}
Result(const Result<void>& other) : m_has_error(other.m_has_error), m_error(other.m_error)
{
}
Result(Result<void>&& other) : m_has_error(other.m_has_error), m_error(other.m_error)
{
}
Result(const Error& err) : m_has_error(true), m_error(err.error)
{
}
bool has_error() const
{
return m_has_error;
}
bool has_value() const
{
return !m_has_error;
}
int error() const
{
expect(has_error(), "Result::error() called on a Result that holds a value");
return m_error;
}
Error release_error() const
{
expect(has_error(), "Result::release_error() called on a Result that holds a value");
return {m_error};
}
const char* error_string() const
{
expect(has_error(), "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error);
}
void value() const
{
expect(has_value(), "Result::value() called on a Result that holds an error");
return;
}
void expect_value(const char* reason) const
{
expect(has_value(), reason);
return;
}
void release_value() const
{
expect(has_value(), "Result::release_value() called on a Result that holds an error");
return;
}
void expect_release_value(const char* reason) const
{
expect(has_value(), reason);
return;
}
private:
bool m_has_error;
int m_error;
};
// clang-format off
#define err(x) Error{x}
// clang-format on
#define TRY(expr) \
({ \
auto _expr_rc = (expr); \
if (!_expr_rc.has_value()) return _expr_rc.release_error(); \
_expr_rc.release_value(); \
})