AsyncTokens.h (7374B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <AppInstallerLogging.h> 5 #include <winrt/Windows.Foundation.h> 6 #include <memory> 7 8 namespace AppInstaller::WinRT 9 { 10 namespace details 11 { 12 // Type erasing interface for winrt cancellation token. 13 struct AsyncCancellationTypeErasure 14 { 15 virtual ~AsyncCancellationTypeErasure() = default; 16 17 virtual bool IsCancelled() const noexcept = 0; 18 virtual void Callback(winrt::delegate<>&& callback) const noexcept = 0; 19 virtual void Cancel() noexcept = 0; 20 }; 21 22 // Type containing winrt cancellation token wrapper. 23 template <typename Promise> 24 struct AsyncCancellationT : public AsyncCancellationTypeErasure 25 { 26 using Token = winrt::impl::cancellation_token<Promise>; 27 28 AsyncCancellationT(Token&& token) : m_token(std::move(token)) {} 29 30 bool IsCancelled() const noexcept override 31 { 32 return m_token(); 33 } 34 35 void Callback(winrt::delegate<>&& callback) const noexcept override 36 { 37 m_token.callback(std::move(callback)); 38 } 39 40 void Cancel() noexcept override 41 { 42 // This is a bit of a hack, but the cancellation_token provides no access to the underlying promise for the purpose of cancellation. 43 static_assert(sizeof(Token) == sizeof(Promise*), "We expect that the cancellation_token has only 1 member and it is a Promise*"); 44 (*reinterpret_cast<Promise**>(&m_token))->Cancel(); 45 } 46 47 private: 48 Token m_token; 49 }; 50 } 51 52 // May hold a cancellation token and provide the ability to check its status. 53 // If empty, it will act as if it is never cancelled. 54 struct AsyncCancellation 55 { 56 // Create an empty cancellation object, which will never be cancelled. 57 AsyncCancellation() = default; 58 59 // Create a cancellation object from the winrt token. 60 template <typename Promise> 61 AsyncCancellation(winrt::impl::cancellation_token<Promise>&& token) 62 { 63 m_token = std::make_shared<details::AsyncCancellationT<Promise>>(std::move(token)); 64 } 65 66 // Returns true if the operation has been cancelled, false if not. 67 bool IsCancelled() const noexcept 68 { 69 return m_token ? m_token->IsCancelled() : false; 70 } 71 72 // Throws the appropriate exception if the operation has been cancelled. 73 void ThrowIfCancelled() const 74 { 75 if (IsCancelled()) 76 { 77 AICLI_LOG(Core, Warning, << "Operation cancelled"); 78 throw winrt::hresult_canceled(); 79 } 80 } 81 82 // Sets a callback that will be invoked on cancellation. 83 void Callback(winrt::delegate<>&& callback) const noexcept 84 { 85 if (m_token) 86 { 87 m_token->Callback(std::move(callback)); 88 } 89 } 90 91 std::weak_ptr<details::AsyncCancellationTypeErasure> GetWeak() 92 { 93 return m_token; 94 } 95 96 private: 97 std::shared_ptr<details::AsyncCancellationTypeErasure> m_token; 98 }; 99 100 namespace details 101 { 102 // Type erasing interface for winrt progress token. 103 template <typename ResultT, typename ProgressT> 104 struct AsyncProgressTypeErasure 105 { 106 virtual ~AsyncProgressTypeErasure() = default; 107 108 virtual void Progress(ProgressT const& progress) const = 0; 109 110 virtual void Result(ResultT const& result) const = 0; 111 }; 112 113 // Type containing winrt progress token wrapper. 114 template <typename Promise, typename ResultT, typename ProgressT> 115 struct AsyncProgressT : public AsyncProgressTypeErasure<ResultT, ProgressT> 116 { 117 using Token = winrt::impl::progress_token<Promise, ProgressT>; 118 119 AsyncProgressT(Token&& token) : m_token(std::move(token)) {} 120 121 void Progress(ProgressT const& progress) const override 122 { 123 m_token(progress); 124 } 125 126 void Result(ResultT const& result) const override 127 { 128 m_token.set_result(result); 129 } 130 131 private: 132 Token m_token; 133 }; 134 135 // Type containing winrt EventHandler. 136 template <typename ResultT, typename ProgressT> 137 struct AsyncProgressEventHandlerT : public AsyncProgressTypeErasure<ResultT, ProgressT> 138 { 139 using Token = winrt::Windows::Foundation::EventHandler<ProgressT>; 140 141 AsyncProgressEventHandlerT(Token&& token) : m_token(std::move(token)) {} 142 143 void Progress(ProgressT const& progress) const override 144 { 145 m_token(m_result, progress); 146 } 147 148 void Result(ResultT const& result) const override 149 { 150 m_result = result; 151 } 152 153 private: 154 mutable ResultT m_result = nullptr; 155 Token m_token; 156 }; 157 } 158 159 // May hold a progress token and provide the ability to send progress updates. 160 // If empty, progress will be dropped on calls here. 161 template <typename ResultT, typename ProgressT> 162 struct AsyncProgress : public AsyncCancellation 163 { 164 // Create an empty progress object. 165 AsyncProgress() = default; 166 167 // Create a progress object from the winrt token. 168 template <typename Promise> 169 AsyncProgress(winrt::impl::progress_token<Promise, ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) : 170 AsyncCancellation(std::move(cancellation)) 171 { 172 m_token = std::make_unique<details::AsyncProgressT<Promise, ResultT, ProgressT>>(std::move(progress)); 173 } 174 175 // Create a progress object from an EventHandler. 176 template <typename Promise> 177 AsyncProgress(winrt::Windows::Foundation::EventHandler<ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) : 178 AsyncCancellation(std::move(cancellation)) 179 { 180 m_token = std::make_unique<details::AsyncProgressEventHandlerT<ResultT, ProgressT>>(std::move(progress)); 181 } 182 183 // Create a cancellation only object. 184 template <typename Promise> 185 AsyncProgress(winrt::impl::cancellation_token<Promise>&& cancellation) : 186 AsyncCancellation(std::move(cancellation)) 187 { 188 } 189 190 // Sends progress if this object is not empty. 191 void Progress(ProgressT const& progress) const 192 { 193 if (m_token) 194 { 195 m_token->Progress(progress); 196 } 197 } 198 199 // Sets the result onto the progress object if it is not empty. 200 void Result(ResultT const& result) const 201 { 202 if (m_token) 203 { 204 m_token->Result(result); 205 } 206 } 207 208 private: 209 std::unique_ptr<details::AsyncProgressTypeErasure<ResultT, ProgressT>> m_token; 210 }; 211 }