diff options
author | Andreas Kling <kling@serenityos.org> | 2021-11-06 01:18:43 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-11-08 00:35:27 +0100 |
commit | c4edb9f6c2cc6755f5e108af93c90e97a4b2e778 (patch) | |
tree | aed4653f0506c99646869d6ed05c17e446b9bc39 /AK | |
parent | 99b8750154ef490c5c07a412d4666e91f643596e (diff) | |
download | serenity-c4edb9f6c2cc6755f5e108af93c90e97a4b2e778.zip |
AK: Add Error and ErrorOr<T>
The goal with these is to eventually replace AK::Result, KResult and
KResultOr<T> with something that works (and makes sense) in both kernel
and userspace.
This first cut of Error can be made from an errno code, or from a string
literal (StringView)
Diffstat (limited to 'AK')
-rw-r--r-- | AK/Error.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/AK/Error.h b/AK/Error.h new file mode 100644 index 0000000000..292594f41d --- /dev/null +++ b/AK/Error.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Format.h> +#include <AK/Optional.h> +#include <AK/StringView.h> + +#if defined(__serenity__) && defined(KERNEL) +# include <LibC/errno_numbers.h> +#else +# include <errno.h> +#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<typename T> +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<T> m_value; + Optional<Error> m_error; +}; + +// Partial specialization for void value type +template<> +class [[nodiscard]] ErrorOr<void> { +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<Error> m_error; +}; + +template<> +struct Formatter<Error> : Formatter<FormatString> { + void format(FormatBuilder& builder, Error const& error) + { + if (error.is_errno()) + return Formatter<FormatString>::format(builder, "Error(errno={})", error.code()); + return Formatter<FormatString>::format(builder, "Error({})", error.string_literal()); + } +}; + +} + +using AK::ErrorOr; |