OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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_COMMON_STRONG_BINDING_SET_H_ |
| 6 #define MOJO_COMMON_STRONG_BINDING_SET_H_ |
| 7 |
| 8 #include <iterator> |
| 9 #include <map> |
| 10 #include <type_traits> |
| 11 #include <utility> |
| 12 |
| 13 #include "base/bind.h" |
| 14 #include "base/logging.h" |
| 15 #include "base/macros.h" |
| 16 #include "mojo/public/cpp/bindings/binding.h" |
| 17 |
| 18 namespace mojo { |
| 19 |
| 20 // A set of mojo services where each service's lifetime is bound to a message |
| 21 // pipe to its client. The template parameter Impl should be a |
| 22 // a concrete implementation of a mojo interface. The InterfaceOverride template |
| 23 // parameter is only required if Impl implements more than one mojo interface. |
| 24 // |
| 25 // To create an instance of Impl in response to a request, call |
| 26 // EmplaceService(std::move(request), <other args to Impl's constructor>); |
| 27 // |
| 28 // When the client of a service closes its connection, that service is |
| 29 // automatically destroyed. set_connection_error_handler() can be used to |
| 30 // register an ErrorHandler to be called when this occurs. When the handler is |
| 31 // called, the service is no longer contained in the set but is only destroyed |
| 32 // after the callback returns. |
| 33 // |
| 34 // A service may be manually destroyed by calling DestroyService(). Services |
| 35 // destroyed this way will not trigger a call to the ErrorHandler. |
| 36 template <typename Impl, typename InterfaceOverride = Impl> |
| 37 class StrongBindingSet { |
| 38 public: |
| 39 using ErrorHandler = Callback<void(Impl*)>; |
| 40 class Iterator; |
| 41 using Interface = typename std::decay<decltype( |
| 42 *std::declval<typename InterfaceOverride::Stub_>().sink())>::type; |
| 43 |
| 44 StrongBindingSet() = default; |
| 45 |
| 46 void set_connection_error_handler(const ErrorHandler& error_handler) { |
| 47 error_handler_ = error_handler; |
| 48 } |
| 49 |
| 50 template <typename... Args> |
| 51 Impl* EmplaceService(InterfaceRequest<Interface> request, |
| 52 Args&&... args) { |
| 53 auto holder = make_scoped_ptr( |
| 54 new Holder(this, std::move(request), std::forward<Args>(args)...)); |
| 55 Impl* impl = holder->impl(); |
| 56 holders_.insert(std::make_pair(impl, std::move(holder))); |
| 57 return impl; |
| 58 } |
| 59 |
| 60 void DestroyService(Impl* impl) { |
| 61 size_t num_erased = holders_.erase(impl); |
| 62 DCHECK_EQ(1u, num_erased); |
| 63 } |
| 64 |
| 65 void Clear() { holders_.clear(); } |
| 66 |
| 67 bool empty() const { return holders_.empty(); } |
| 68 size_t size() const { return holders_.size(); } |
| 69 Iterator begin() const { return Iterator(holders_.begin()); } |
| 70 Iterator end() const { return Iterator(holders_.end()); } |
| 71 |
| 72 private: |
| 73 class Holder; |
| 74 using Container = std::map<Impl*, scoped_ptr<Holder>>; |
| 75 |
| 76 void OnConnectionError(Holder* holder) { |
| 77 Impl* impl = holder->impl(); |
| 78 auto it = holders_.find(holder->impl()); |
| 79 DCHECK(it != holders_.end()); |
| 80 scoped_ptr<Holder> holder_owner = std::move(it->second); |
| 81 holders_.erase(it); |
| 82 if (!error_handler_.is_null()) |
| 83 error_handler_.Run(impl); |
| 84 } |
| 85 |
| 86 ErrorHandler error_handler_; |
| 87 Container holders_; |
| 88 |
| 89 DISALLOW_COPY_AND_ASSIGN(StrongBindingSet); |
| 90 }; |
| 91 |
| 92 template <typename Impl, typename Interface> |
| 93 class StrongBindingSet<Impl, Interface>::Holder { |
| 94 public: |
| 95 template <typename... Args> |
| 96 Holder(StrongBindingSet* service_set, |
| 97 InterfaceRequest<Interface> request, |
| 98 Args&&... args) |
| 99 : impl_(std::forward<Args>(args)...), |
| 100 binding_(&impl_, std::move(request)), |
| 101 service_set_(service_set) { |
| 102 binding_.set_connection_error_handler( |
| 103 base::Bind(&Holder::OnConnectionError, base::Unretained(this))); |
| 104 } |
| 105 |
| 106 void OnConnectionError() { service_set_->OnConnectionError(this); } |
| 107 |
| 108 Impl* impl() { return &impl_; } |
| 109 |
| 110 private: |
| 111 Impl impl_; |
| 112 Binding<Interface> binding_; |
| 113 |
| 114 // Owns this. |
| 115 StrongBindingSet* const service_set_; |
| 116 |
| 117 DISALLOW_COPY_AND_ASSIGN(Holder); |
| 118 }; |
| 119 |
| 120 template <typename Impl, typename Interface> |
| 121 class StrongBindingSet<Impl, Interface>::Iterator |
| 122 : public std::iterator<std::bidirectional_iterator_tag, Impl*> { |
| 123 public: |
| 124 Iterator() = default; |
| 125 |
| 126 Iterator& operator++() { |
| 127 ++it_; |
| 128 return *this; |
| 129 } |
| 130 |
| 131 Iterator operator++(int) { return Iterator(it_++); } |
| 132 |
| 133 Iterator& operator--() { |
| 134 --it_; |
| 135 return *this; |
| 136 } |
| 137 |
| 138 Iterator operator--(int) { return Iterator(it_--); } |
| 139 |
| 140 Impl* operator*() const { return it_->first; } |
| 141 Impl* operator->() const { return it_->first; } |
| 142 bool operator==(const Iterator& other) const { return it_ == other.it_; } |
| 143 bool operator!=(const Iterator& other) const { return it_ != other.it_; } |
| 144 |
| 145 private: |
| 146 using IteratorImpl = typename Container::const_iterator; |
| 147 friend class StrongBindingSet; |
| 148 |
| 149 explicit Iterator(IteratorImpl it) : it_(it) {} |
| 150 |
| 151 IteratorImpl it_; |
| 152 }; |
| 153 |
| 154 } // namespace mojo |
| 155 |
| 156 #endif // MOJO_COMMON_STRONG_BINDING_SET_H_ |
OLD | NEW |