xref: /aosp_15_r20/external/cronet/base/win/async_operation.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_WIN_ASYNC_OPERATION_H_
6 #define BASE_WIN_ASYNC_OPERATION_H_
7 
8 #include <unknwn.h>
9 
10 #include <windows.foundation.h>
11 #include <wrl/async.h>
12 #include <wrl/client.h>
13 
14 #include <type_traits>
15 #include <utility>
16 
17 #include "base/functional/bind.h"
18 #include "base/functional/callback.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/threading/thread_checker.h"
21 #include "base/win/winrt_foundation_helpers.h"
22 
23 namespace base {
24 namespace win {
25 
26 // This file provides an implementation of Windows::Foundation::IAsyncOperation.
27 // Specializations exist for "regular" types and interface types that inherit
28 // from IUnknown. Both specializations expose a callback() method, which can be
29 // used to provide the result that will be forwarded to the registered
30 // completion handler. For regular types it expects an instance of that type,
31 // and for interface types it expects a corresponding ComPtr. This class is
32 // thread-affine and all member methods should be called on the same thread that
33 // constructed the object. In order to offload heavy result computation,
34 // base's PostTaskAndReplyWithResult() should be used with the ResultCallback
35 // passed as a reply.
36 //
37 // Example usages:
38 //
39 // // Regular types
40 // auto regular_op = WRL::Make<base::win::AsyncOperation<int>>();
41 // auto cb = regular_op->callback();
42 // regular_op->put_Completed(...event handler...);
43 // ...
44 // // This will invoke the event handler.
45 // std::move(cb).Run(123);
46 // ...
47 // // Results can be queried:
48 // int results = 0;
49 // regular_op->GetResults(&results);
50 // EXPECT_EQ(123, results);
51 //
52 // // Interface types
53 // auto interface_op = WRL::Make<base::win::AsyncOperation<FooBar*>>();
54 // auto cb = interface_op->callback();
55 // interface_op->put_Completed(...event handler...);
56 // ...
57 // // This will invoke the event handler.
58 // std::move(cb).Run(WRL::Make<IFooBarImpl>());
59 // ...
60 // // Results can be queried:
61 // WRL::ComPtr<IFooBar> results;
62 // interface_op->GetResults(&results);
63 // // |results| points to the provided IFooBarImpl instance.
64 //
65 // // Offloading a heavy computation:
66 // auto my_op = WRL::Make<base::win::AsyncOperation<FooBar*>>();
67 // base::ThreadPool::PostTaskAndReplyWithResult(
68 //     base::BindOnce(MakeFooBar), my_op->callback());
69 
70 namespace internal {
71 
72 // Template tricks needed to dispatch to the correct implementation below.
73 // See base/win/winrt_foundation_helpers.h for explanation.
74 
75 template <typename T>
76 using AsyncOperationComplex =
77     typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex;
78 
79 template <typename T>
80 using AsyncOperationAbi = AbiType<AsyncOperationComplex<T>>;
81 
82 template <typename T>
83 using AsyncOperationOptionalStorage =
84     OptionalStorageType<AsyncOperationComplex<T>>;
85 
86 template <typename T>
87 using AsyncOperationStorage = StorageType<AsyncOperationComplex<T>>;
88 
89 }  // namespace internal
90 
91 template <class T>
92 class AsyncOperation
93     : public Microsoft::WRL::RuntimeClass<
94           Microsoft::WRL::RuntimeClassFlags<
95               Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
96           ABI::Windows::Foundation::IAsyncOperation<T>> {
97  public:
98   using AbiT = internal::AsyncOperationAbi<T>;
99   using OptionalStorageT = internal::AsyncOperationOptionalStorage<T>;
100   using StorageT = internal::AsyncOperationStorage<T>;
101   using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>;
102   using ResultCallback = base::OnceCallback<void(StorageT)>;
103 
AsyncOperation()104   AsyncOperation() {
105     // Note: This can't be done in the constructor initializer list. This is
106     // because it relies on weak_factory_ to be initialized, which needs to be
107     // the last class member. Also applies below.
108     callback_ =
109         base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr());
110   }
111 
112   AsyncOperation(const AsyncOperation&) = delete;
113   AsyncOperation& operator=(const AsyncOperation&) = delete;
114 
~AsyncOperation()115   ~AsyncOperation() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
116 
117   // ABI::Windows::Foundation::IAsyncOperation:
put_Completed(Handler * handler)118   IFACEMETHODIMP put_Completed(Handler* handler) override {
119     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
120     handler_ = handler;
121     return S_OK;
122   }
get_Completed(Handler ** handler)123   IFACEMETHODIMP get_Completed(Handler** handler) override {
124     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
125     return handler_.CopyTo(handler);
126   }
GetResults(AbiT * results)127   IFACEMETHODIMP GetResults(AbiT* results) override {
128     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
129     return results_ ? internal::CopyTo(results_, results) : E_PENDING;
130   }
131 
callback()132   ResultCallback callback() {
133     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
134     DCHECK(!callback_.is_null());
135     return std::move(callback_);
136   }
137 
138  private:
InvokeCompletedHandler()139   void InvokeCompletedHandler() {
140     handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed);
141   }
142 
OnResult(StorageT result)143   void OnResult(StorageT result) {
144     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
145     DCHECK(!results_);
146     results_ = std::move(result);
147     InvokeCompletedHandler();
148   }
149 
150   ResultCallback callback_;
151   Microsoft::WRL::ComPtr<Handler> handler_;
152   OptionalStorageT results_;
153 
154   THREAD_CHECKER(thread_checker_);
155   base::WeakPtrFactory<AsyncOperation> weak_factory_{this};
156 };
157 
158 }  // namespace win
159 }  // namespace base
160 
161 #endif  // BASE_WIN_ASYNC_OPERATION_H_
162