233 lines
4.9 KiB
C++
233 lines
4.9 KiB
C++
#pragma once
|
|
#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;
|
|
m_has_error = false;
|
|
}
|
|
|
|
Result(T&& value) : m_value(move(value))
|
|
{
|
|
m_has_value = true;
|
|
m_has_error = false;
|
|
}
|
|
|
|
Result(const Result<T>& other) : m_value(other.m_value)
|
|
{
|
|
if (!other.m_has_error)
|
|
{
|
|
m_has_value = true;
|
|
m_has_error = false;
|
|
}
|
|
else
|
|
{
|
|
m_has_error = true;
|
|
m_has_value = false;
|
|
m_error = other.m_error;
|
|
}
|
|
}
|
|
|
|
Result(Result<T>&& other) : m_value(move(other.m_value))
|
|
{
|
|
if (!other.m_has_error)
|
|
{
|
|
m_has_value = true;
|
|
m_has_error = false;
|
|
}
|
|
else
|
|
{
|
|
m_has_error = true;
|
|
m_has_value = false;
|
|
m_error = other.m_error;
|
|
}
|
|
}
|
|
|
|
Result(const Error& err) : m_value()
|
|
{
|
|
m_error = err.error;
|
|
m_has_error = true;
|
|
m_has_value = false;
|
|
}
|
|
|
|
bool has_error()
|
|
{
|
|
return m_has_error;
|
|
}
|
|
|
|
bool has_value()
|
|
{
|
|
return m_has_value;
|
|
}
|
|
|
|
int error()
|
|
{
|
|
expect(has_error(), "Result::error() called on a Result that holds a value");
|
|
return m_error;
|
|
}
|
|
|
|
Error release_error()
|
|
{
|
|
expect(has_error(), "Result::release_error() called on a Result that holds a value");
|
|
return {m_error};
|
|
}
|
|
|
|
const char* error_string()
|
|
{
|
|
expect(has_error(), "Result::error_string() called on a Result that holds a value");
|
|
return ::error_string(m_error);
|
|
}
|
|
|
|
T value()
|
|
{
|
|
expect(has_value(), "Result::value() called on a Result that holds an error");
|
|
return m_value.value();
|
|
}
|
|
|
|
T expect_value(const char* reason)
|
|
{
|
|
expect(has_value(), reason);
|
|
return move(m_value.release_value());
|
|
}
|
|
|
|
T value_or(const T& other)
|
|
{
|
|
return m_value.value_or(other);
|
|
}
|
|
|
|
bool try_set_value(T& ref)
|
|
{
|
|
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;
|
|
int m_error;
|
|
bool m_has_error;
|
|
bool m_has_value;
|
|
};
|
|
|
|
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_error = err.error;
|
|
m_has_error = true;
|
|
}
|
|
|
|
bool has_error()
|
|
{
|
|
return m_has_error;
|
|
}
|
|
|
|
bool has_value()
|
|
{
|
|
return !m_has_error;
|
|
}
|
|
|
|
int error()
|
|
{
|
|
expect(has_error(), "Result::error() called on a Result that holds a value");
|
|
return m_error;
|
|
}
|
|
|
|
Error release_error()
|
|
{
|
|
expect(has_error(), "Result::release_error() called on a Result that holds a value");
|
|
return {m_error};
|
|
}
|
|
|
|
const char* error_string()
|
|
{
|
|
expect(has_error(), "Result::error_string() called on a Result that holds a value");
|
|
return ::error_string(m_error);
|
|
}
|
|
|
|
void value()
|
|
{
|
|
expect(has_value(), "Result::value() called on a Result that holds an error");
|
|
return;
|
|
}
|
|
|
|
void expect_value(const char* reason)
|
|
{
|
|
expect(has_value(), reason);
|
|
return;
|
|
}
|
|
|
|
void release_value()
|
|
{
|
|
expect(has_value(), "Result::release_value() called on a Result that holds an error");
|
|
return;
|
|
}
|
|
|
|
void expect_release_value(const char* reason)
|
|
{
|
|
expect(has_value(), reason);
|
|
return;
|
|
}
|
|
|
|
private:
|
|
int m_error;
|
|
bool m_has_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.expect_release_value("sanity check failed: has_error() returned false, yet result has no value"); \
|
|
})
|