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..dc66860b4e0d78fba19a3de4727f59bb6e235a59 100644 |
--- a/mojo/public/cpp/bindings/binding_set.h |
+++ b/mojo/public/cpp/bindings/binding_set.h |
@@ -5,107 +5,172 @@ |
#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() { |
+ DCHECK(binding_set_->SupportsContext()); |
+ binding_set_->SetDispatchContext(context_); |
+ } |
void OnConnectionError() { |
- base::Closure error_handler = error_handler_; |
- delete this; |
- if (!error_handler.is_null()) |
- error_handler.Run(); |
+ if (binding_set_->SupportsContext()) |
+ 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); |
}; |