/* * 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 ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_object, DOM::ExceptionOr& result) { if (result.is_exception()) { result.materialized_exception(global_object) .visit( [&](NonnullRefPtr dom_exception) { vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, move(dom_exception))); }, [&](auto* js_exception) { vm.throw_exception(global_object, js_exception); }); return true; } return false; } namespace Detail { 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; }; } template using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType::Type; // Return type depends on the return type of 'fn' (when invoked with no args): // void or ExceptionOr: Optional, always returns JS::js_undefined() // ExceptionOr: Optional // T: Optional template()()), typename Ret = Conditional && !IsVoid, T, ExtractExceptionOrValueType>> Optional throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn) { if constexpr (IsExceptionOr) { auto&& result = fn(); if (throw_dom_exception(vm, global_object, result)) return {}; 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(); } } template bool should_return_empty(const Optional& value) { if constexpr (IsSame) return !value.has_value() || value.value().is_empty(); return !value.has_value(); } }