ExceptionOrUtils.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * Copyright (c) 2021-2023, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Optional.h>
  8. #include <LibJS/Runtime/VM.h>
  9. #include <LibWeb/WebIDL/ExceptionOr.h>
  10. namespace Web::Bindings {
  11. template<typename>
  12. constexpr bool IsExceptionOr = false;
  13. template<typename T>
  14. constexpr bool IsExceptionOr<WebIDL::ExceptionOr<T>> = true;
  15. template<typename>
  16. constexpr bool IsThrowCompletionOr = false;
  17. template<typename T>
  18. constexpr bool IsThrowCompletionOr<JS::ThrowCompletionOr<T>> = true;
  19. namespace Detail {
  20. template<typename T>
  21. struct ExtractExceptionOrValueType {
  22. using Type = T;
  23. };
  24. template<typename T>
  25. struct ExtractExceptionOrValueType<WebIDL::ExceptionOr<T>> {
  26. using Type = T;
  27. };
  28. template<typename T>
  29. struct ExtractExceptionOrValueType<JS::ThrowCompletionOr<T>> {
  30. using Type = T;
  31. };
  32. template<>
  33. struct ExtractExceptionOrValueType<void> {
  34. using Type = JS::Value;
  35. };
  36. template<>
  37. struct ExtractExceptionOrValueType<WebIDL::ExceptionOr<Empty>> {
  38. using Type = JS::Value;
  39. };
  40. template<>
  41. struct ExtractExceptionOrValueType<WebIDL::ExceptionOr<void>> {
  42. using Type = JS::Value;
  43. };
  44. }
  45. ALWAYS_INLINE JS::Completion dom_exception_to_throw_completion(JS::VM& vm, auto&& exception)
  46. {
  47. return exception.visit(
  48. [&](WebIDL::SimpleException const& exception) {
  49. auto message = exception.message.visit([](auto const& s) -> StringView { return s; });
  50. switch (exception.type) {
  51. #define E(x) \
  52. case WebIDL::SimpleExceptionType::x: \
  53. return vm.template throw_completion<JS::x>(message);
  54. ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E)
  55. #undef E
  56. default:
  57. VERIFY_NOT_REACHED();
  58. }
  59. },
  60. [&](JS::NonnullGCPtr<WebIDL::DOMException> const& exception) {
  61. return throw_completion(exception);
  62. },
  63. [&](JS::Completion const& completion) {
  64. return completion;
  65. });
  66. }
  67. template<typename T>
  68. using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType<T>::Type;
  69. // Return type depends on the return type of 'fn' (when invoked with no args):
  70. // void or ExceptionOr<void>: JS::ThrowCompletionOr<JS::Value>, always returns JS::js_undefined()
  71. // ExceptionOr<T>: JS::ThrowCompletionOr<T>
  72. // T: JS::ThrowCompletionOr<T>
  73. template<typename F, typename T = decltype(declval<F>()()), typename Ret = Conditional<!IsExceptionOr<T> && !IsVoid<T> && !IsThrowCompletionOr<T>, T, ExtractExceptionOrValueType<T>>>
  74. JS::ThrowCompletionOr<Ret> throw_dom_exception_if_needed(JS::VM& vm, F&& fn)
  75. {
  76. if constexpr (IsExceptionOr<T>) {
  77. auto&& result = fn();
  78. if (result.is_exception())
  79. return dom_exception_to_throw_completion(vm, result.exception());
  80. if constexpr (requires(T v) { v.value(); })
  81. return result.value();
  82. else
  83. return JS::js_undefined();
  84. } else if constexpr (IsVoid<T>) {
  85. fn();
  86. return JS::js_undefined();
  87. } else {
  88. return fn();
  89. }
  90. }
  91. }