forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[base] Provide IAsyncOperation Implementation
This change implements Windows::Foundation::IAsyncOperation. It provides a simple interface and allows clients to specify desired results via a callback. This is mostly useful for tests, when custom fake implementations of UWP interfaces are required. Some of these implementations must provide Async methods, that return an instantiation of IAsyncOperation. Bug: 821766 Change-Id: I728c0bb5311898fac4ee5f5e54d8a64b2aa61d94 Reviewed-on: https://chromium-review.googlesource.com/984194 Reviewed-by: Robert Liao <robliao@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org> Cr-Commit-Position: refs/heads/master@{#551811}
- Loading branch information
Showing
3 changed files
with
420 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef BASE_WIN_ASYNC_OPERATION_H_ | ||
#define BASE_WIN_ASYNC_OPERATION_H_ | ||
|
||
#include <unknwn.h> | ||
#include <windows.foundation.h> | ||
#include <wrl/async.h> | ||
#include <wrl/client.h> | ||
|
||
#include <type_traits> | ||
#include <utility> | ||
|
||
#include "base/bind.h" | ||
#include "base/callback.h" | ||
#include "base/macros.h" | ||
#include "base/memory/weak_ptr.h" | ||
#include "base/optional.h" | ||
#include "base/threading/thread_checker.h" | ||
|
||
namespace base { | ||
namespace win { | ||
|
||
// This file provides an implementation of Windows::Foundation::IAsyncOperation. | ||
// Specializations exist for "regular" types and interface types that inherit | ||
// from IUnknown. Both specializations expose a callback() method, which can be | ||
// used to provide the result that will be forwarded to the registered | ||
// completion handler. For regular types it expects an instance of that type, | ||
// and for interface types it expects a corresponding ComPtr. This class is | ||
// thread-affine and all member methods should be called on the same thread that | ||
// constructed the object. In order to offload heavy result computation, | ||
// base's PostTaskAndReplyWithResult() should be used with the ResultCallback | ||
// passed as a reply. | ||
// | ||
// Example usages: | ||
// | ||
// // Regular types | ||
// auto regular_op = WRL::Make<base::win::AsyncOperation<int>>(); | ||
// auto cb = regular_op->callback(); | ||
// regular_op->put_Completed(...event handler...); | ||
// ... | ||
// // This will invoke the event handler. | ||
// std::move(cb).Run(123); | ||
// ... | ||
// // Results can be queried: | ||
// int results = 0; | ||
// regular_op->GetResults(&results); | ||
// EXPECT_EQ(123, results); | ||
// | ||
// // Interface types | ||
// auto interface_op = WRL::Make<base::win::AsyncOperation<FooBar*>>(); | ||
// auto cb = interface_op->callback(); | ||
// interface_op->put_Completed(...event handler...); | ||
// ... | ||
// // This will invoke the event handler. | ||
// std::move(cb).Run(WRL::Make<IFooBarImpl>()); | ||
// ... | ||
// // Results can be queried: | ||
// WRL::ComPtr<IFooBar> results; | ||
// interface_op->GetResults(&results); | ||
// // |results| points to the provided IFooBarImpl instance. | ||
// | ||
// // Offloading a heavy computation: | ||
// auto my_op = WRL::Make<base::win::AsyncOperation<FooBar*>>(); | ||
// base::PostTaskAndReplyWithResult( | ||
// base::BindOnce(MakeFooBar), my_op->callback()); | ||
|
||
namespace internal { | ||
|
||
// Template tricks needed to dispatch to the correct implementation below. | ||
// | ||
// For all types which are neither InterfaceGroups nor RuntimeClasses, the | ||
// following three typedefs are synonyms for a single C++ type. But for | ||
// InterfaceGroups and RuntimeClasses, they are different types: | ||
// LogicalT: The C++ Type for the InterfaceGroup or RuntimeClass, when | ||
// used as a template parameter. Eg "RCFoo*" | ||
// AbiT: The C++ type for the default interface used to represent the | ||
// InterfaceGroup or RuntimeClass when passed as a method parameter. | ||
// Eg "IFoo*" | ||
// ComplexT: An instantiation of the Internal "AggregateType" template that | ||
// combines LogicalT with AbiT. Eg "AggregateType<RCFoo*,IFoo*>" | ||
// | ||
// windows.foundation.collections.h defines the following template and | ||
// semantics in Windows::Foundation::Internal: | ||
// | ||
// template <class LogicalType, class AbiType> | ||
// struct AggregateType; | ||
// | ||
// LogicalType - the Windows Runtime type (eg, runtime class, inteface group, | ||
// etc) being provided as an argument to an _impl template, when | ||
// that type cannot be represented at the ABI. | ||
// AbiType - the type used for marshalling, ie "at the ABI", for the | ||
// logical type. | ||
template <typename T> | ||
using ComplexT = | ||
typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex; | ||
|
||
template <typename T> | ||
using AbiT = | ||
typename ABI::Windows::Foundation::Internal::GetAbiType<ComplexT<T>>::type; | ||
|
||
template <typename T> | ||
using LogicalT = typename ABI::Windows::Foundation::Internal::GetLogicalType< | ||
ComplexT<T>>::type; | ||
|
||
template <typename T> | ||
using InterfaceT = std::remove_pointer_t<AbiT<T>>; | ||
|
||
// Implementation of shared functionality. | ||
template <class T> | ||
class AsyncOperationBase | ||
: public Microsoft::WRL::RuntimeClass< | ||
Microsoft::WRL::RuntimeClassFlags< | ||
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, | ||
ABI::Windows::Foundation::IAsyncOperation<T>> { | ||
public: | ||
using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>; | ||
|
||
AsyncOperationBase() = default; | ||
~AsyncOperationBase() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } | ||
|
||
// ABI::Windows::Foundation::IAsyncOperation: | ||
IFACEMETHODIMP put_Completed(Handler* handler) override { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
handler_ = handler; | ||
return S_OK; | ||
} | ||
|
||
IFACEMETHODIMP get_Completed(Handler** handler) override { | ||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | ||
return handler_.CopyTo(handler); | ||
} | ||
|
||
protected: | ||
void InvokeCompletedHandler() { | ||
handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); | ||
} | ||
|
||
THREAD_CHECKER(thread_checker_); | ||
|
||
private: | ||
Microsoft::WRL::ComPtr<Handler> handler_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(AsyncOperationBase); | ||
}; | ||
|
||
} // namespace internal | ||
|
||
template <typename T, typename Enable = void> | ||
class AsyncOperation; | ||
|
||
template <typename T> | ||
class AsyncOperation< | ||
T, | ||
std::enable_if_t<std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>> | ||
: public internal::AsyncOperationBase<T> { | ||
public: | ||
using InterfacePointer = Microsoft::WRL::ComPtr<internal::InterfaceT<T>>; | ||
using ResultCallback = base::OnceCallback<void(InterfacePointer)>; | ||
|
||
AsyncOperation() : weak_factory_(this) { | ||
// Note: This can't be done in the constructor initializer list. This is | ||
// because it relies on weak_factory_ to be initialized, which needs to be | ||
// the last class member. Also applies below. | ||
callback_ = | ||
base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr()); | ||
} | ||
|
||
ResultCallback callback() { | ||
// Note: `this->` here and below is necessary due to the | ||
// -Wmicrosoft-template compiler warning. | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
DCHECK(!callback_.is_null()); | ||
return std::move(callback_); | ||
} | ||
|
||
// ABI::Windows::Foundation::IAsyncOperation: | ||
IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
return ptr_ ? ptr_.CopyTo(results) : E_PENDING; | ||
} | ||
|
||
private: | ||
void OnResult(InterfacePointer ptr) { | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
DCHECK(!ptr_); | ||
ptr_ = std::move(ptr); | ||
this->InvokeCompletedHandler(); | ||
} | ||
|
||
ResultCallback callback_; | ||
InterfacePointer ptr_; | ||
base::WeakPtrFactory<AsyncOperation> weak_factory_; | ||
}; | ||
|
||
template <typename T> | ||
class AsyncOperation< | ||
T, | ||
std::enable_if_t< | ||
!std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>> | ||
: public internal::AsyncOperationBase<T> { | ||
public: | ||
using ResultCallback = base::OnceCallback<void(T)>; | ||
|
||
AsyncOperation() : weak_factory_(this) { | ||
callback_ = | ||
base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr()); | ||
} | ||
|
||
ResultCallback callback() { | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
DCHECK(!callback_.is_null()); | ||
return std::move(callback_); | ||
} | ||
|
||
// ABI::Windows::Foundation::IAsyncOperation: | ||
IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
if (!value_) | ||
return E_PENDING; | ||
|
||
*results = *value_; | ||
return S_OK; | ||
} | ||
|
||
private: | ||
void OnResult(T result) { | ||
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | ||
DCHECK(!value_); | ||
value_.emplace(std::move(result)); | ||
this->InvokeCompletedHandler(); | ||
} | ||
|
||
ResultCallback callback_; | ||
base::Optional<T> value_; | ||
base::WeakPtrFactory<AsyncOperation> weak_factory_; | ||
}; | ||
|
||
} // namespace win | ||
} // namespace base | ||
|
||
#endif // BASE_WIN_ASYNC_OPERATION_H_ |
Oops, something went wrong.