Luna/libluna/include/luna/Result.h

279 lines
7.0 KiB
C
Raw Normal View History

2022-11-13 11:20:53 +00:00
#pragma once
#define _LUNA_SYSTEM_ERROR_EXTENSIONS
#include <luna/Check.h>
#include <luna/Move.h>
2022-12-08 15:08:18 +00:00
#include <luna/Option.h>
#include <luna/PlacementNew.h>
#include <luna/SystemError.h>
#include <luna/Types.h>
2022-11-13 11:20:53 +00:00
struct Error
{
Error(int err)
{
error = err;
}
int error;
};
template <typename T> class Result
{
public:
Result(const T& value) : m_value(value)
2022-11-13 11:20:53 +00:00
{
}
Result(T&& value) : m_value(move(value))
2022-11-13 11:20:53 +00:00
{
}
Result(const Result<T>& other) : m_value(other.m_value), m_error(other.m_error)
2022-11-13 11:20:53 +00:00
{
}
Result(Result<T>&& other) : m_value(move(other.m_value)), m_error(other.m_error)
2022-11-13 11:20:53 +00:00
{
}
Result(const Error& err) : m_value(), m_error(err.error)
2022-11-13 11:20:53 +00:00
{
}
2022-12-30 18:06:47 +00:00
Result<T>& operator=(const Result<T>& other)
{
if (this == &other) return *this;
m_error = other.m_error;
m_value = other.m_value;
return *this;
}
Result<T>& operator=(Result<T>&& other)
{
if (this == &other) return *this;
m_error = other.m_error;
m_value = move(other.m_value);
return *this;
}
bool has_error() const
2022-11-13 11:20:53 +00:00
{
return !m_value.has_value();
2022-11-13 11:20:53 +00:00
}
bool has_value() const
2022-11-13 11:20:53 +00:00
{
return m_value.has_value();
2022-11-13 11:20:53 +00:00
}
int error(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_error(), caller, "Result::error() called on a Result that holds a value");
2022-11-13 11:20:53 +00:00
return m_error;
}
Error release_error(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_error(), caller, "Result::release_error() called on a Result that holds a value");
2022-12-21 19:22:44 +00:00
return { m_error };
2022-11-13 11:20:53 +00:00
}
const char* error_string(SourceLocation caller = SourceLocation::current()) const
{
expect_at(has_error(), caller, "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error);
}
T value(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_value(), caller, "Result::value() called on a Result that holds an error");
return m_value.unchecked_value({});
2022-11-13 11:20:53 +00:00
}
T expect_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{
expect_at(has_value(), caller, reason);
return m_value.unchecked_value({});
}
T value_or(const T& other) const
2022-11-13 11:20:53 +00:00
{
2022-12-08 15:08:18 +00:00
return m_value.value_or(other);
2022-11-13 11:20:53 +00:00
}
bool try_set_value(T& ref) const
{
2022-12-08 15:08:18 +00:00
return m_value.try_set_value(ref);
}
bool try_set_value_or_error(T& ref, int& err) const
{
bool ok = m_value.try_set_value(ref);
if (!ok) err = m_error;
return ok;
}
bool try_move_value(T& ref)
{
return m_value.try_move_value(ref);
}
bool try_move_value_or_error(T& ref, int& err)
{
bool ok = m_value.try_move_value(ref);
if (!ok) err = m_error;
return ok;
}
T release_value(SourceLocation caller = SourceLocation::current())
2022-11-13 11:20:53 +00:00
{
expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error");
return m_value.unchecked_release_value({});
2022-11-13 11:20:53 +00:00
}
T expect_release_value(const char* reason, SourceLocation caller = SourceLocation::current())
{
expect_at(has_value(), caller, reason);
return m_value.unchecked_release_value({});
2022-11-13 11:20:53 +00:00
}
static Result<T> from_option(Option<T>&& option, int error)
{
if (option.has_value()) { return option.unchecked_release_value({}); }
else
return Error { error };
}
2023-04-07 08:56:49 +00:00
static Result<T> from_syscall(long rc)
{
if (rc < 0) return Error { (int)-rc };
else
return (T)rc;
}
2022-11-13 11:20:53 +00:00
private:
2022-12-08 15:08:18 +00:00
Option<T> m_value;
int m_error;
2022-11-13 11:20:53 +00:00
};
template <> class Result<void>
{
public:
Result() : m_has_error(false)
2022-11-13 11:20:53 +00:00
{
}
Result(const Result<void>& other) : m_has_error(other.m_has_error), m_error(other.m_error)
2022-11-13 11:20:53 +00:00
{
}
Result(Result<void>&& other) : m_has_error(other.m_has_error), m_error(other.m_error)
2022-11-13 11:20:53 +00:00
{
}
Result(const Error& err) : m_has_error(true), m_error(err.error)
2022-11-13 11:20:53 +00:00
{
}
2022-12-30 18:06:47 +00:00
Result<void>& operator=(const Result<void>& other)
{
if (this == &other) return *this;
m_has_error = other.m_has_error;
m_error = other.m_error;
return *this;
}
Result<void>& operator=(Result<void>&& other)
{
if (this == &other) return *this;
m_has_error = other.m_has_error;
m_error = other.m_error;
return *this;
}
2022-11-13 11:20:53 +00:00
static Result<void> from_syscall(long rc)
{
2023-04-18 16:49:55 +00:00
if (rc < 0) return Error { (int)-rc };
return {};
}
bool has_error() const
2022-11-13 11:20:53 +00:00
{
return m_has_error;
}
bool has_value() const
2022-11-13 11:20:53 +00:00
{
return !m_has_error;
}
int error(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_error(), caller, "Result::error() called on a Result that holds a value");
2022-11-13 11:20:53 +00:00
return m_error;
}
Error release_error(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_error(), caller, "Result::release_error() called on a Result that holds a value");
2022-12-21 19:22:44 +00:00
return { m_error };
2022-11-13 11:20:53 +00:00
}
const char* error_string(SourceLocation caller = SourceLocation::current()) const
{
expect_at(has_error(), caller, "Result::error_string() called on a Result that holds a value");
return ::error_string(m_error);
}
void value(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_value(), caller, "Result::value() called on a Result that holds an error");
2022-11-13 11:20:53 +00:00
}
void expect_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{
expect_at(has_value(), caller, reason);
}
void release_value(SourceLocation caller = SourceLocation::current()) const
2022-11-13 11:20:53 +00:00
{
expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error");
2022-11-13 11:20:53 +00:00
}
void expect_release_value(const char* reason, SourceLocation caller = SourceLocation::current()) const
{
expect_at(has_value(), caller, reason);
}
2022-11-13 11:20:53 +00:00
private:
bool m_has_error;
int m_error;
2022-11-13 13:29:15 +00:00
};
// clang-format off
#define err(x) Error{x}
// clang-format on
#define TRY(expr) \
({ \
auto _expr_rc = (expr); \
2022-12-08 15:08:18 +00:00
if (!_expr_rc.has_value()) return _expr_rc.release_error(); \
_expr_rc.release_value(); \
})
2022-12-30 17:46:27 +00:00
template <typename T> inline Result<T*> nonnull_or_error(T* ptr, int error)
{
if (ptr == nullptr) return err(error);
else
return ptr;
2023-01-02 12:07:29 +00:00
}