summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/WebIDL/ExceptionOr.h
blob: 7b54991099fa896e01c813f392826d31b3634076 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/RefPtr.h>
#include <LibJS/Runtime/Completion.h>
#include <LibWeb/WebIDL/DOMException.h>

namespace Web::WebIDL {

#define ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) \
    E(EvalError)                                   \
    E(RangeError)                                  \
    E(ReferenceError)                              \
    E(TypeError)                                   \
    E(URIError)

#define E(x) x,
enum class SimpleExceptionType {
    ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E)
};
#undef E

struct SimpleException {
    SimpleExceptionType type;
    Variant<String, StringView> message;
};

template<typename ValueType>
class [[nodiscard]] ExceptionOr {
public:
    ExceptionOr()
    requires(IsSame<ValueType, Empty>)
        : m_result_or_exception(Empty {})
    {
    }

    ExceptionOr(ValueType const& result)
        : m_result_or_exception(result)
    {
    }

    ExceptionOr(ValueType&& result)
        : m_result_or_exception(move(result))
    {
    }

    // Allows implicit construction of ExceptionOr<T> from a type U if T(U) is a supported constructor.
    // Most commonly: Value from Object* or similar, so we can omit the curly braces from "return { TRY(...) };".
    // Disabled for POD types to avoid weird conversion shenanigans.
    template<typename WrappedValueType>
    ExceptionOr(WrappedValueType result)
    requires(!IsPOD<ValueType>)
        : m_result_or_exception(ValueType { move(result) })
    {
    }

    ExceptionOr(JS::NonnullGCPtr<DOMException> exception)
        : m_result_or_exception(exception)
    {
    }

    ExceptionOr(SimpleException exception)
        : m_result_or_exception(move(exception))
    {
    }

    ExceptionOr(JS::Completion exception)
        : m_result_or_exception(move(exception))
    {
        auto const& completion = m_result_or_exception.template get<JS::Completion>();
        VERIFY(completion.is_error());
    }

    ExceptionOr(Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> exception)
        : m_result_or_exception(move(exception))
    {
        if (auto* completion = m_result_or_exception.template get_pointer<JS::Completion>())
            VERIFY(completion->is_error());
    }

    ExceptionOr(ExceptionOr&& other) = default;
    ExceptionOr(ExceptionOr const& other) = default;
    ~ExceptionOr() = default;

    ValueType& value()
    requires(!IsSame<ValueType, Empty>)
    {
        return m_result_or_exception.template get<ValueType>();
    }

    ValueType release_value()
    {
        return move(m_result_or_exception.template get<ValueType>());
    }

    Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> exception() const
    {
        return m_result_or_exception.template downcast<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion>();
    }

    bool is_exception() const
    {
        return !m_result_or_exception.template has<ValueType>();
    }

    ValueType release_value_but_fixme_should_propagate_errors()
    {
        VERIFY(!is_error());
        return release_value();
    }

    // These are for compatibility with the TRY() macro in AK.
    [[nodiscard]] bool is_error() const { return is_exception(); }
    Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> release_error() { return exception(); }

private:
    // https://webidl.spec.whatwg.org/#idl-exceptions
    Variant<ValueType, SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> m_result_or_exception;
};

template<>
class [[nodiscard]] ExceptionOr<void> : public ExceptionOr<Empty> {
public:
    using ExceptionOr<Empty>::ExceptionOr;
};

}