/* * Copyright (c) 2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #if defined(__serenity__) && defined(KERNEL) # include #else # include # include #endif namespace AK { class Error { public: static Error from_errno(int code) { return Error(code); } static Error from_syscall(StringView syscall_name, int rc) { return Error(syscall_name, rc); } static Error from_string_literal(StringView string_literal) { return Error(string_literal); } bool operator==(Error const& other) const { return m_code == other.m_code && m_string_literal == other.m_string_literal && m_syscall == other.m_syscall; } bool is_errno() const { return m_code != 0; } bool is_syscall() const { return m_syscall; } int code() const { return m_code; } StringView string_literal() const { return m_string_literal; } protected: Error(int code) : m_code(code) { } private: Error(StringView string_literal) : m_string_literal(string_literal) { } Error(StringView syscall_name, int rc) : m_code(-rc) , m_string_literal(syscall_name) , m_syscall(true) { } int m_code { 0 }; StringView m_string_literal; bool m_syscall { false }; }; template class [[nodiscard]] ErrorOr final : public Variant { public: using Variant::Variant; template ALWAYS_INLINE ErrorOr(U&& value) requires(!IsSame, ErrorOr>) : Variant(forward(value)) { } #ifdef __serenity__ ErrorOr(ErrnoCode code) : Variant(Error::from_errno(code)) { } #endif T& value() { return this->template get(); } T const& value() const { return this->template get(); } ErrorType& error() { return this->template get(); } ErrorType const& error() const { return this->template get(); } bool is_error() const { return this->template has(); } T release_value() { return move(value()); } ErrorType release_error() { return move(error()); } T release_value_but_fixme_should_propagate_errors() { VERIFY(!is_error()); return release_value(); } private: // 'downcast' is fishy in this context. Let's hide it by making it private. using Variant::downcast; }; // Partial specialization for void value type template class [[nodiscard]] ErrorOr { public: ErrorOr(ErrorType error) : m_error(move(error)) { } #ifdef __serenity__ ErrorOr(ErrnoCode code) : m_error(Error::from_errno(code)) { } #endif ErrorOr() = default; ErrorOr(ErrorOr&& other) = default; ErrorOr(ErrorOr const& other) = default; ~ErrorOr() = default; ErrorOr& operator=(ErrorOr&& other) = default; ErrorOr& operator=(ErrorOr const& other) = default; ErrorType& error() { return m_error.value(); } bool is_error() const { return m_error.has_value(); } ErrorType release_error() { return m_error.release_value(); } void release_value() { } private: Optional m_error; }; } using AK::Error; using AK::ErrorOr;