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..6add930800c96ee89f417349b079138ec4714e3d 100644 |
| --- a/mojo/public/cpp/bindings/binding_set.h |
| +++ b/mojo/public/cpp/bindings/binding_set.h |
| @@ -5,107 +5,138 @@ |
| #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); |
| + } |
| +}; |
| + |
| // 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: |
| + using Traits = BindingSetTraits<BindingType>; |
| + using ProxyType = typename Traits::ProxyType; |
| + using RequestType = typename Traits::RequestType; |
| + |
| BindingSet() {} |
| - ~BindingSet() { CloseAllBindings(); } |
| 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()); |
| + void AddBinding(Interface* impl, |
| + RequestType request, |
| + void* context = nullptr) { |
| + 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)); |
|
yzshen1
2016/08/26 16:30:48
Is it intentional that we don't provide a similar
Ken Rockot(use gerrit already)
2016/08/26 17:01:20
It's not possible to implement since we wouldn't k
yzshen1
2016/08/26 18:11:28
Right. I don't think it is that important to suppo
|
| + return proxy; |
| } |
| - void CloseAllBindings() { |
| - for (const auto& it : bindings_) { |
| - if (it) { |
| - it->Close(); |
| - delete it.get(); |
| - } |
| - } |
| - bindings_.clear(); |
| - } |
| + void CloseAllBindings() {} |
|
yzshen1
2016/08/26 16:30:48
Why this is a non-op?
Ken Rockot(use gerrit already)
2016/08/26 17:01:20
Oops :> Fixed
|
| bool empty() const { return bindings_.empty(); } |
| + // Implementations may call this when processing a dispatched message. During |
| + // the extent of a message dispatch (or connection error handler invocation), |
| + // this will return the context associated with the binding which received |
| + // the message (or error.) Use AddBinding() to associated a context with a |
| + // specific binding. |
| + void* dispatch_context() const { 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) { |
| + binding_.AddFilter(base::MakeUnique<DispatchFilter>(this)); |
|
yzshen1
2016/08/26 16:30:48
Do we expect that setting context is a common oper
Ken Rockot(use gerrit already)
2016/08/26 17:01:20
Seems reasonable. I've added a mojo::BindingSetDis
|
| + 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; |
| + } |
| + |
| + Entry* entry_; |
| - void set_connection_error_handler(const base::Closure& error_handler) { |
| - error_handler_ = error_handler; |
| - } |
| + DISALLOW_COPY_AND_ASSIGN(DispatchFilter); |
| + }; |
| - base::WeakPtr<Element> GetWeakPtr() { |
| - return weak_ptr_factory_.GetWeakPtr(); |
| + void WillDispatch() { |
| + binding_set_->set_dispatch_context(context_); |
| } |
| - void Close() { binding_.Close(); } |
| - |
| 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 set_dispatch_context(void* context) { dispatch_context_ = 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(); |
| } |
| 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); |
| }; |