Chromium Code Reviews| Index: mojo/public/cpp/bindings/binding_set.h |
| diff --git a/mojo/public/cpp/bindings/binding_set.h b/mojo/public/cpp/bindings/binding_set.h |
| index b1baca6a808dc3e6e637bbd408e7f424dfae828d..8b36669c799e095379e76994403d108970dc8238 100644 |
| --- a/mojo/public/cpp/bindings/binding_set.h |
| +++ b/mojo/public/cpp/bindings/binding_set.h |
| @@ -5,107 +5,171 @@ |
| #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ |
| #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ |
| -#include <algorithm> |
| #include <utility> |
| -#include <vector> |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/macros.h" |
| -#include "base/memory/weak_ptr.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| +#include "mojo/public/cpp/bindings/interface_ptr.h" |
| +#include "mojo/public/cpp/bindings/interface_request.h" |
| +#include "mojo/public/cpp/bindings/message.h" |
| namespace mojo { |
| +template <typename BindingType> |
| +struct BindingSetTraits; |
| + |
| +template <typename Interface> |
| +struct BindingSetTraits<Binding<Interface>> { |
| + using ProxyType = InterfacePtr<Interface>; |
| + using RequestType = InterfaceRequest<Interface>; |
| + |
| + static RequestType GetProxy(ProxyType* proxy) { |
| + return mojo::GetProxy(proxy); |
| + } |
| +}; |
| + |
| +enum class BindingSetDispatchMode { |
| + WITHOUT_CONTEXT, |
| + WITH_CONTEXT, |
| +}; |
| + |
| // Use this class to manage a set of bindings, which are automatically destroyed |
| // and removed from the set when the pipe they are bound to is disconnected. |
| -template <typename Interface> |
| +template <typename Interface, typename BindingType = Binding<Interface>> |
| class BindingSet { |
| public: |
| - BindingSet() {} |
| - ~BindingSet() { CloseAllBindings(); } |
| + using Traits = BindingSetTraits<BindingType>; |
| + using ProxyType = typename Traits::ProxyType; |
| + using RequestType = typename Traits::RequestType; |
| + |
| + BindingSet() : BindingSet(BindingSetDispatchMode::WITHOUT_CONTEXT) {} |
| + |
| + // Constructs a new BindingSet operating in |dispatch_mode|. If |WITH_CONTEXT| |
| + // is used, AddBinding() supports a |context| argument, and dispatch_context() |
| + // may be called during message or error dispatch to identify which specific |
| + // binding received the message or error. |
| + explicit BindingSet(BindingSetDispatchMode dispatch_mode) |
| + : dispatch_mode_(dispatch_mode) {} |
| void set_connection_error_handler(const base::Closure& error_handler) { |
| error_handler_ = error_handler; |
| } |
| - void AddBinding(Interface* impl, InterfaceRequest<Interface> request) { |
| - auto binding = new Element(impl, std::move(request)); |
| - binding->set_connection_error_handler( |
| - base::Bind(&BindingSet::OnConnectionError, base::Unretained(this))); |
| - bindings_.push_back(binding->GetWeakPtr()); |
| + // Adds a new binding to the set which binds |request| to |impl|. If |context| |
| + // is non-null, dispatch_context() will reflect this value during the extent |
| + // of any message or error dispatch targeting this specific binding. Note that |
| + // |context| may only be non-null if the BindingSet was constructed with |
| + // |BindingSetDispatchMode::WITH_CONTEXT|. |
| + void AddBinding(Interface* impl, |
| + RequestType request, |
| + void* context = nullptr) { |
| + DCHECK(!context || SupportsContext()); |
| + std::unique_ptr<Entry> entry = |
| + base::MakeUnique<Entry>(impl, std::move(request), this, context); |
| + bindings_.insert(std::make_pair(entry.get(), std::move(entry))); |
| } |
| - // Returns an InterfacePtr bound to one end of a pipe whose other end is |
| - // bound to |this|. |
| - InterfacePtr<Interface> CreateInterfacePtrAndBind(Interface* impl) { |
| - InterfacePtr<Interface> interface_ptr; |
| - AddBinding(impl, GetProxy(&interface_ptr)); |
| - return interface_ptr; |
| + // Returns a proxy bound to one end of a pipe whose other end is bound to |
| + // |this|. |
| + ProxyType CreateInterfacePtrAndBind(Interface* impl) { |
| + ProxyType proxy; |
| + AddBinding(impl, Traits::GetProxy(&proxy)); |
| + return proxy; |
| } |
| - void CloseAllBindings() { |
| - for (const auto& it : bindings_) { |
| - if (it) { |
| - it->Close(); |
| - delete it.get(); |
| - } |
| - } |
| - bindings_.clear(); |
| - } |
| + void CloseAllBindings() { bindings_.clear(); } |
| bool empty() const { return bindings_.empty(); } |
| + // Implementations may call this when processing a dispatched message or |
| + // error. During the extent of message or error dispatch, this will return the |
| + // context associated with the specific binding which received the message or |
| + // error. Use AddBinding() to associated a context with a specific binding. |
| + // |
| + // Note that this may ONLY be called if the BindingSet was constructed with |
| + // |BindingSetDispatchMode::WITH_CONTEXT|. |
| + void* dispatch_context() const { |
| + DCHECK(SupportsContext()); |
| + return dispatch_context_; |
| + } |
| + |
| private: |
| - class Element { |
| + friend class Entry; |
| + |
| + class Entry { |
| public: |
| - Element(Interface* impl, InterfaceRequest<Interface> request) |
| - : binding_(impl, std::move(request)), weak_ptr_factory_(this) { |
| - binding_.set_connection_error_handler( |
| - base::Bind(&Element::OnConnectionError, base::Unretained(this))); |
| + Entry(Interface* impl, |
| + RequestType request, |
| + BindingSet* binding_set, |
| + void* context) |
| + : binding_(impl, std::move(request)), |
| + binding_set_(binding_set), |
| + context_(context) { |
| + if (binding_set->SupportsContext()) |
| + binding_.AddFilter(base::MakeUnique<DispatchFilter>(this)); |
| + binding_.set_connection_error_handler(base::Bind( |
| + &Entry::OnConnectionError, base::Unretained(this))); |
| } |
| - ~Element() {} |
| + private: |
| + class DispatchFilter : public MessageReceiver { |
| + public: |
| + explicit DispatchFilter(Entry* entry) : entry_(entry) {} |
| + ~DispatchFilter() override {} |
| + |
| + private: |
| + // MessageReceiver: |
| + bool Accept(Message* message) override { |
| + entry_->WillDispatch(); |
| + return true; |
| + } |
| - void set_connection_error_handler(const base::Closure& error_handler) { |
| - error_handler_ = error_handler; |
| - } |
| + Entry* entry_; |
| - base::WeakPtr<Element> GetWeakPtr() { |
| - return weak_ptr_factory_.GetWeakPtr(); |
| - } |
| + DISALLOW_COPY_AND_ASSIGN(DispatchFilter); |
| + }; |
| - void Close() { binding_.Close(); } |
| + void WillDispatch() { |
| + if (binding_set_->SupportsContext()) |
|
yzshen1
2016/08/26 18:11:28
nit: we could move this check out of WillDispatch(
Ken Rockot(use gerrit already)
2016/08/26 20:15:01
Done
|
| + binding_set_->SetDispatchContext(context_); |
| + } |
| void OnConnectionError() { |
| - base::Closure error_handler = error_handler_; |
| - delete this; |
| - if (!error_handler.is_null()) |
| - error_handler.Run(); |
| + WillDispatch(); |
| + binding_set_->OnConnectionError(this); |
| } |
| - private: |
| - Binding<Interface> binding_; |
| - base::Closure error_handler_; |
| - base::WeakPtrFactory<Element> weak_ptr_factory_; |
| + BindingType binding_; |
| + BindingSet* const binding_set_; |
| + void* const context_; |
| - DISALLOW_COPY_AND_ASSIGN(Element); |
| + DISALLOW_COPY_AND_ASSIGN(Entry); |
| }; |
| - void OnConnectionError() { |
| - // Clear any deleted bindings. |
| - bindings_.erase(std::remove_if(bindings_.begin(), bindings_.end(), |
| - [](const base::WeakPtr<Element>& p) { |
| - return p.get() == nullptr; |
| - }), |
| - bindings_.end()); |
| + void SetDispatchContext(void* context) { |
| + DCHECK(SupportsContext()); |
| + dispatch_context_ = context; |
| + } |
| + |
| + bool SupportsContext() const { |
| + return dispatch_mode_ == BindingSetDispatchMode::WITH_CONTEXT; |
| + } |
| + |
| + void OnConnectionError(Entry* entry) { |
| + auto it = bindings_.find(entry); |
| + DCHECK(it != bindings_.end()); |
| + bindings_.erase(it); |
| if (!error_handler_.is_null()) |
| error_handler_.Run(); |
| } |
| + BindingSetDispatchMode dispatch_mode_; |
| base::Closure error_handler_; |
| - std::vector<base::WeakPtr<Element>> bindings_; |
| + std::map<Entry*, std::unique_ptr<Entry>> bindings_; |
| + void* dispatch_context_ = nullptr; |
| DISALLOW_COPY_AND_ASSIGN(BindingSet); |
| }; |