blob: 2147301e7619a49ce22c2dbc974ffd7ac6edef77 [file] [log] [blame]
// Copyright 2014 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_CPP_BINDINGS_BINDING_SET_H_
#define LIB_FIDL_CPP_BINDINGS_BINDING_SET_H_
#include <assert.h>
#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
#include "lib/fxl/macros.h"
#include "lib/fidl/cpp/bindings/binding.h"
namespace fidl {
// Use this class to manage a set of bindings each of which is
// owned by the channel it is bound to.
//
// The implementation type of the binding is also parameterized, allowing
// the use of smart pointer types such as |std::unique_ptr<>| to reference
// the implementation.
template <typename Interface, typename ImplPtr = Interface*>
class BindingSet {
public:
using Binding = ::fidl::Binding<Interface, ImplPtr>;
using StorageType = std::vector<std::unique_ptr<Binding>>;
using iterator = typename StorageType::iterator;
using const_iterator = typename StorageType::const_iterator;
BindingSet() {}
~BindingSet() { CloseAllBindings(); }
// Adds a binding to the list and arranges for it to be removed when
// a connection error occurs. Does not take ownership of |impl|, which
// must outlive the binding set.
void AddBinding(ImplPtr impl, InterfaceRequest<Interface> request) {
bindings_.emplace_back(
new Binding(std::forward<ImplPtr>(impl), std::move(request)));
auto* binding = bindings_.back().get();
// Set the connection error handler for the newly added Binding to be a
// function that will erase it from the vector.
binding->set_connection_error_handler(
std::bind(&BindingSet::RemoveOnError, this, binding));
}
// Adds a binding to the list and arranges for it to be removed when
// a connection error occurs. Does not take ownership of |impl|, which
// must outlive the binding set.
InterfaceHandle<Interface> AddBinding(ImplPtr impl) {
bindings_.emplace_back(new Binding(std::forward<ImplPtr>(impl)));
auto* binding = bindings_.back().get();
InterfaceHandle<Interface> interface;
binding->Bind(&interface);
// Set the connection error handler for the newly added Binding to be a
// function that will erase it from the vector.
binding->set_connection_error_handler(
std::bind(&BindingSet::RemoveOnError, this, binding));
return std::move(interface);
}
void CloseAllBindings() { bindings_.clear(); }
size_t size() const { return bindings_.size(); }
void set_on_empty_set_handler(fxl::Closure on_empty_set_handler) {
on_empty_set_handler_ = std::move(on_empty_set_handler);
}
// NOTE: These iterators return a ref to a std::unique_ptr<fidl::Binding<>>.
// The ImplPtr type is available by calling fidl::Binding<>::impl(). For
// example:
//
// auto impl_ptr = (*it)->impl();
//
// Iterators may be invalidated when a Binding in the set encounters a
// connection error, as that causes removal from internal storage which is
// backed by a std::vector<>.
iterator begin() { return bindings_.begin(); }
const_iterator begin() const { return bindings_.begin(); }
iterator end() { return bindings_.end(); }
const_iterator end() const { return bindings_.end(); }
private:
void RemoveOnError(Binding* binding) {
auto it = std::find_if(bindings_.begin(), bindings_.end(),
[binding](const std::unique_ptr<Binding>& b) {
return (b.get() == binding);
});
assert(it != bindings_.end());
bindings_.erase(it);
if (bindings_.empty() && on_empty_set_handler_)
on_empty_set_handler_();
}
StorageType bindings_;
fxl::Closure on_empty_set_handler_;
FXL_DISALLOW_COPY_AND_ASSIGN(BindingSet);
};
} // namespace fidl
#endif // LIB_FIDL_CPP_BINDINGS_BINDING_SET_H_