ExceptionOrUtils.h 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Optional.h>
  8. #include <AK/StdLibExtras.h>
  9. #include <LibJS/Runtime/VM.h>
  10. #include <LibWeb/Bindings/DOMExceptionWrapper.h>
  11. #include <LibWeb/DOM/ExceptionOr.h>
  12. namespace Web::Bindings {
  13. template<typename>
  14. constexpr bool IsExceptionOr = false;
  15. template<typename T>
  16. constexpr bool IsExceptionOr<DOM::ExceptionOr<T>> = true;
  17. template<typename T>
  18. ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_object, DOM::ExceptionOr<T>& result)
  19. {
  20. if (result.is_exception()) {
  21. result.materialized_exception(global_object)
  22. .visit(
  23. [&](NonnullRefPtr<DOM::DOMException> dom_exception) { vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, move(dom_exception))); },
  24. [&](auto* js_exception) { vm.throw_exception(global_object, js_exception); });
  25. return true;
  26. }
  27. return false;
  28. }
  29. namespace Detail {
  30. template<typename T>
  31. struct ExtractExceptionOrValueType {
  32. using Type = T;
  33. };
  34. template<typename T>
  35. struct ExtractExceptionOrValueType<DOM::ExceptionOr<T>> {
  36. using Type = T;
  37. };
  38. template<>
  39. struct ExtractExceptionOrValueType<void> {
  40. using Type = JS::Value;
  41. };
  42. template<>
  43. struct ExtractExceptionOrValueType<DOM::ExceptionOr<Empty>> {
  44. using Type = JS::Value;
  45. };
  46. template<>
  47. struct ExtractExceptionOrValueType<DOM::ExceptionOr<void>> {
  48. using Type = JS::Value;
  49. };
  50. }
  51. template<typename T>
  52. using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType<T>::Type;
  53. // Return type depends on the return type of 'fn' (when invoked with no args):
  54. // void or ExceptionOr<void>: Optional<JS::Value>, always returns JS::js_undefined()
  55. // ExceptionOr<T>: Optional<T>
  56. // T: Optional<T>
  57. template<typename F, typename T = decltype(declval<F>()()), typename Ret = Conditional<!IsExceptionOr<T> && !IsVoid<T>, T, ExtractExceptionOrValueType<T>>>
  58. Optional<Ret> throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn)
  59. {
  60. if constexpr (IsExceptionOr<T>) {
  61. auto&& result = fn();
  62. if (throw_dom_exception(vm, global_object, result))
  63. return {};
  64. if constexpr (requires(T v) { v.value(); })
  65. return result.value();
  66. else
  67. return JS::js_undefined();
  68. } else if constexpr (IsVoid<T>) {
  69. fn();
  70. return JS::js_undefined();
  71. } else {
  72. return fn();
  73. }
  74. }
  75. template<typename T>
  76. bool should_return_empty(const Optional<T>& value)
  77. {
  78. if constexpr (IsSame<JS::Value, T>)
  79. return !value.has_value() || value.value().is_empty();
  80. return !value.has_value();
  81. }
  82. }