/* * Copyright (c) 2021-2023, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace Web::Bindings { template constexpr bool IsExceptionOr = false; template constexpr bool IsExceptionOr> = true; template constexpr bool IsThrowCompletionOr = false; template constexpr bool IsThrowCompletionOr> = true; namespace Detail { template struct ExtractExceptionOrValueType { using Type = T; }; template struct ExtractExceptionOrValueType> { using Type = T; }; template struct ExtractExceptionOrValueType> { using Type = T; }; template<> struct ExtractExceptionOrValueType { using Type = JS::Value; }; template<> struct ExtractExceptionOrValueType> { using Type = JS::Value; }; template<> struct ExtractExceptionOrValueType> { using Type = JS::Value; }; ALWAYS_INLINE JS::Completion dom_exception_to_throw_completion(JS::VM& vm, auto&& exception) { return exception.visit( [&](WebIDL::SimpleException const& exception) { auto message = exception.message.visit([](auto const& s) -> StringView { return s; }); switch (exception.type) { #define E(x) \ case WebIDL::SimpleExceptionType::x: \ return vm.template throw_completion(message); ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) #undef E default: VERIFY_NOT_REACHED(); } }, [&](JS::NonnullGCPtr const& exception) { return throw_completion(exception); }, [&](JS::Completion const& completion) { return completion; }); } } template using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType::Type; // Return type depends on the return type of 'fn' (when invoked with no args): // void or ExceptionOr: JS::ThrowCompletionOr, always returns JS::js_undefined() // ExceptionOr: JS::ThrowCompletionOr // T: JS::ThrowCompletionOr template()()), typename Ret = Conditional && !IsVoid && !IsThrowCompletionOr, T, ExtractExceptionOrValueType>> JS::ThrowCompletionOr throw_dom_exception_if_needed(JS::VM& vm, F&& fn) { if constexpr (IsExceptionOr) { auto&& result = fn(); if (result.is_exception()) return Detail::dom_exception_to_throw_completion(vm, result.exception()); if constexpr (requires(T v) { v.value(); }) return result.value(); else return JS::js_undefined(); } else if constexpr (IsVoid) { fn(); return JS::js_undefined(); } else { return fn(); } } }