1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#ifndef AsyncRequest_h
28#define AsyncRequest_h
29
30#include <wtf/Function.h>
31#include <wtf/HashMap.h>
32#include <wtf/RefCounted.h>
33#include <wtf/RefPtr.h>
34
35namespace WebKit {
36
37class AsyncRequest : public RefCounted<AsyncRequest> {
38public:
39 virtual ~AsyncRequest();
40
41 uint64_t requestID() { return m_requestID; }
42
43 void setAbortHandler(WTF::Function<void ()>&&);
44 void requestAborted();
45 template<typename... Arguments> void completeRequest(Arguments&&... arguments);
46
47protected:
48 explicit AsyncRequest(WTF::Function<void ()>&& abortHandler);
49
50 virtual void clearCompletionHandler() = 0;
51
52 WTF::Function<void ()> m_abortHandler;
53
54private:
55 uint64_t m_requestID;
56};
57
58template <typename... Arguments>
59class AsyncRequestImpl final : public AsyncRequest {
60public:
61 template<typename T> using ArgumentType = typename std::conditional<std::is_integral<T>::value, T, const T&>::type;
62
63 static Ref<AsyncRequest> create(WTF::Function<void(ArgumentType<Arguments>...)>&& completionHandler)
64 {
65 return adoptRef(*new AsyncRequestImpl<Arguments...>(WTFMove(completionHandler), nullptr));
66 }
67
68 static Ref<AsyncRequest> create(WTF::Function<void(ArgumentType<Arguments>...)>&& completionHandler, WTF::Function<void()>&& abortHandler)
69 {
70 return adoptRef(*new AsyncRequestImpl<Arguments...>(WTFMove(completionHandler), WTFMove(abortHandler)));
71 }
72
73 virtual ~AsyncRequestImpl()
74 {
75 ASSERT(!m_completionHandler);
76 }
77
78 template<typename... RequestArguments>
79 void completeRequest(RequestArguments&&... arguments)
80 {
81 m_completionHandler(std::forward<RequestArguments>(arguments)...);
82 m_completionHandler = nullptr;
83 }
84
85private:
86 AsyncRequestImpl(WTF::Function<void (ArgumentType<Arguments>...)>&& completionHandler, WTF::Function<void ()>&& abortHandler)
87 : AsyncRequest(WTFMove(abortHandler))
88 , m_completionHandler(WTFMove(completionHandler))
89 {
90 ASSERT(m_completionHandler);
91 }
92
93 void clearCompletionHandler() override
94 {
95 m_completionHandler = nullptr;
96 }
97
98 WTF::Function<void (ArgumentType<Arguments>...)> m_completionHandler;
99};
100
101template<typename... Arguments> void AsyncRequest::completeRequest(Arguments&&... arguments)
102{
103 auto* request = static_cast<AsyncRequestImpl<typename std::decay<Arguments>::type...>*>(this);
104 request->completeRequest(std::forward<Arguments>(arguments)...);
105 m_abortHandler = nullptr;
106}
107
108class AsyncRequestMap {
109public:
110 using RequestMap = HashMap<uint64_t, RefPtr<AsyncRequest>>;
111
112 AsyncRequestMap()
113#ifndef NDEBUG
114 : m_lastRequestIDTaken(std::numeric_limits<uint64_t>::max())
115#endif
116 { }
117
118 Ref<AsyncRequest> take(uint64_t requestID)
119 {
120#ifndef NDEBUG
121 ASSERT_WITH_MESSAGE(requestID != m_lastRequestIDTaken, "Attempt to take the same AsyncRequest twice in a row. A background queue might have dispatched both an error callback and a success callback?");
122 m_lastRequestIDTaken = requestID;
123#endif
124
125 RefPtr<AsyncRequest> request = m_requestMap.take(requestID);
126 RELEASE_ASSERT(request);
127
128 return adoptRef(*request.leakRef());
129 }
130
131 void add(uint64_t requestID, RefPtr<AsyncRequest>&& request)
132 {
133 m_requestMap.add(requestID, WTFMove(request));
134 }
135
136 void clear()
137 {
138 m_requestMap.clear();
139 }
140
141 typename RequestMap::ValuesIteratorRange values()
142 {
143 return m_requestMap.values();
144 }
145
146private:
147 RequestMap m_requestMap;
148#ifndef NDEBUG
149 uint64_t m_lastRequestIDTaken;
150#endif
151};
152
153} // namespace WebKit
154
155#endif // AsyncRequest_h
156