/* * Copyright (c) 2021-2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Web::WebIDL { #define ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) \ E(EvalError) \ E(RangeError) \ E(ReferenceError) \ E(TypeError) \ E(URIError) #define E(x) x, enum class SimpleExceptionType { ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) }; #undef E struct SimpleException { SimpleExceptionType type; Variant message; }; template class [[nodiscard]] ExceptionOr { public: ExceptionOr() requires(IsSame) : m_result_or_exception(Empty {}) { } ExceptionOr(ValueType const& result) : m_result_or_exception(result) { } ExceptionOr(ValueType&& result) : m_result_or_exception(move(result)) { } // Allows implicit construction of ExceptionOr from a type U if T(U) is a supported constructor. // Most commonly: Value from Object* or similar, so we can omit the curly braces from "return { TRY(...) };". // Disabled for POD types to avoid weird conversion shenanigans. template ExceptionOr(WrappedValueType result) requires(!IsPOD) : m_result_or_exception(ValueType { move(result) }) { } ExceptionOr(JS::NonnullGCPtr exception) : m_result_or_exception(exception) { } ExceptionOr(SimpleException exception) : m_result_or_exception(move(exception)) { } ExceptionOr(JS::Completion exception) : m_result_or_exception(move(exception)) { auto const& completion = m_result_or_exception.template get(); VERIFY(completion.is_error()); } ExceptionOr(Variant, JS::Completion> exception) : m_result_or_exception(move(exception)) { if (auto* completion = m_result_or_exception.template get_pointer()) VERIFY(completion->is_error()); } ExceptionOr(ExceptionOr&& other) = default; ExceptionOr(ExceptionOr const& other) = default; ~ExceptionOr() = default; ValueType& value() requires(!IsSame) { return m_result_or_exception.template get(); } ValueType release_value() { return move(m_result_or_exception.template get()); } Variant, JS::Completion> exception() const { return m_result_or_exception.template downcast, JS::Completion>(); } bool is_exception() const { return !m_result_or_exception.template has(); } ValueType release_value_but_fixme_should_propagate_errors() { VERIFY(!is_error()); return release_value(); } // These are for compatibility with the TRY() macro in AK. [[nodiscard]] bool is_error() const { return is_exception(); } Variant, JS::Completion> release_error() { return exception(); } private: // https://webidl.spec.whatwg.org/#idl-exceptions Variant, JS::Completion> m_result_or_exception; }; template<> class [[nodiscard]] ExceptionOr : public ExceptionOr { public: using ExceptionOr::ExceptionOr; }; }