1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
7 
8 #include <algorithm>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "mojo/public/cpp/bindings/binding.h"
17 
18 namespace mojo {
19 
20 // Use this class to manage a set of bindings, which are automatically destroyed
21 // and removed from the set when the pipe they are bound to is disconnected.
22 template <typename Interface>
23 class BindingSet {
24  public:
BindingSet()25   BindingSet() {}
~BindingSet()26   ~BindingSet() { CloseAllBindings(); }
27 
set_connection_error_handler(const base::Closure & error_handler)28   void set_connection_error_handler(const base::Closure& error_handler) {
29     error_handler_ = error_handler;
30   }
31 
AddBinding(Interface * impl,InterfaceRequest<Interface> request)32   void AddBinding(Interface* impl, InterfaceRequest<Interface> request) {
33     auto binding = new Element(impl, std::move(request));
34     binding->set_connection_error_handler(
35         base::Bind(&BindingSet::OnConnectionError, base::Unretained(this)));
36     bindings_.push_back(binding->GetWeakPtr());
37   }
38 
39   // Returns an InterfacePtr bound to one end of a pipe whose other end is
40   // bound to |this|.
CreateInterfacePtrAndBind(Interface * impl)41   InterfacePtr<Interface> CreateInterfacePtrAndBind(Interface* impl) {
42     InterfacePtr<Interface> interface_ptr;
43     AddBinding(impl, GetProxy(&interface_ptr));
44     return interface_ptr;
45   }
46 
CloseAllBindings()47   void CloseAllBindings() {
48     for (const auto& it : bindings_) {
49       if (it) {
50         it->Close();
51         delete it.get();
52       }
53     }
54     bindings_.clear();
55   }
56 
empty()57   bool empty() const { return bindings_.empty(); }
58 
59  private:
60   class Element {
61    public:
Element(Interface * impl,InterfaceRequest<Interface> request)62     Element(Interface* impl, InterfaceRequest<Interface> request)
63         : binding_(impl, std::move(request)), weak_ptr_factory_(this) {
64       binding_.set_connection_error_handler(
65           base::Bind(&Element::OnConnectionError, base::Unretained(this)));
66     }
67 
~Element()68     ~Element() {}
69 
set_connection_error_handler(const base::Closure & error_handler)70     void set_connection_error_handler(const base::Closure& error_handler) {
71       error_handler_ = error_handler;
72     }
73 
GetWeakPtr()74     base::WeakPtr<Element> GetWeakPtr() {
75       return weak_ptr_factory_.GetWeakPtr();
76     }
77 
Close()78     void Close() { binding_.Close(); }
79 
OnConnectionError()80     void OnConnectionError() {
81       base::Closure error_handler = error_handler_;
82       delete this;
83       if (!error_handler.is_null())
84         error_handler.Run();
85     }
86 
87    private:
88     Binding<Interface> binding_;
89     base::Closure error_handler_;
90     base::WeakPtrFactory<Element> weak_ptr_factory_;
91 
92     DISALLOW_COPY_AND_ASSIGN(Element);
93   };
94 
OnConnectionError()95   void OnConnectionError() {
96     // Clear any deleted bindings.
97     bindings_.erase(std::remove_if(bindings_.begin(), bindings_.end(),
98                                    [](const base::WeakPtr<Element>& p) {
99                                      return p.get() == nullptr;
100                                    }),
101                     bindings_.end());
102 
103     if (!error_handler_.is_null())
104       error_handler_.Run();
105   }
106 
107   base::Closure error_handler_;
108   std::vector<base::WeakPtr<Element>> bindings_;
109 
110   DISALLOW_COPY_AND_ASSIGN(BindingSet);
111 };
112 
113 }  // namespace mojo
114 
115 #endif  // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
116