/* * Copyright (c) 2021, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #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(auto&& global_object, auto&& exception) { auto& vm = global_object.vm(); return exception.visit( [&](DOM::SimpleException const& exception) { switch (exception.type) { #define E(x) \ case DOM::SimpleExceptionType::x: \ return vm.template throw_completion(global_object, exception.message); ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) #undef E default: VERIFY_NOT_REACHED(); } }, [&](NonnullRefPtr exception) { return vm.template throw_completion(global_object, move(exception)); }); } } 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(auto&& global_object, F&& fn) { if constexpr (IsExceptionOr) { auto&& result = fn(); if (result.is_exception()) return Detail::dom_exception_to_throw_completion(global_object, 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(); } } }