diff --git a/AK/Error.h b/AK/Error.h new file mode 100644 index 00000000000..292594f41dc --- /dev/null +++ b/AK/Error.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +#if defined(__serenity__) && defined(KERNEL) +# include +#else +# include +#endif + +namespace AK { + +class Error { +public: + static Error from_errno(int code) { return Error(code); } + static Error from_string_literal(StringView string_literal) { return Error(string_literal); } + + bool is_errno() const { return m_code != 0; } + + int code() const { return m_code; } + StringView string_literal() const { return m_string_literal; } + +private: + Error(int code) + : m_code(code) + { + } + + Error(StringView string_literal) + : m_string_literal(string_literal) + { + } + + int m_code { 0 }; + StringView m_string_literal; +}; + +template +class [[nodiscard]] ErrorOr { +public: + ErrorOr(T const& value) + : m_value(value) + { + } + + ErrorOr(T&& value) + : m_value(move(value)) + { + } + + ErrorOr(ErrnoCode errno) + : m_error(Error::from_errno(errno)) + { + } + + ErrorOr(Error&& error) + : m_error(move(error)) + { + } + + ErrorOr(ErrorOr&& other) = default; + ErrorOr(ErrorOr const& other) = default; + ~ErrorOr() = default; + + T& value() { return m_value.value(); } + Error& error() { return m_error.value(); } + + bool is_error() const { return m_error.has_value(); } + + T release_value() { return m_value.release_value(); } + Error release_error() { return m_error.release_value(); } + +private: + Optional m_value; + Optional m_error; +}; + +// Partial specialization for void value type +template<> +class [[nodiscard]] ErrorOr { +public: + ErrorOr(Error error) + : m_error(move(error)) + { + } + + ErrorOr() = default; + ErrorOr(ErrorOr&& other) = default; + ErrorOr(const ErrorOr& other) = default; + ~ErrorOr() = default; + + Error& error() { return m_error.value(); } + bool is_error() const { return m_error.has_value(); } + Error release_error() { return m_error.release_value(); } + +private: + Optional m_error; +}; + +template<> +struct Formatter : Formatter { + void format(FormatBuilder& builder, Error const& error) + { + if (error.is_errno()) + return Formatter::format(builder, "Error(errno={})", error.code()); + return Formatter::format(builder, "Error({})", error.string_literal()); + } +}; + +} + +using AK::ErrorOr;