blob: 9c70b6147bf199d5f1b645f2fc8aa532d95526fc [file] [log] [blame]
// Copyright 2016 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 PERIDOT_LIB_BOUND_SET_BOUND_SET_H_
#define PERIDOT_LIB_BOUND_SET_BOUND_SET_H_
#include <vector>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/interface_ptr.h>
#include <src/lib/fxl/logging.h>
namespace modular {
// "Specialization" (overload) covering unique_ptr.
template <typename T>
T* GetFidlType(std::unique_ptr<T>* p) {
return p->get();
}
// General implementation intended to cover Binding and StrongBinding.
template <typename FidlType, typename UniqueType = FidlType*>
UniqueType Identify(FidlType* binding) {
return binding;
}
// An extensible/derivable InterfacePtrSet/(Strong)BindingSet that contains a
// collection of objects of type T that contain FidlTypes (e.g. InterfacePtr,
// Binding, or StrongBinding). Elements are automatically removed from the
// collection and destroyed when their associated Channel experiences a
// connection error. When the set is destroyed all of the Channels will be
// closed.
//
// Unlike the Fidl library InterfacePtrSet and (Strong)BindingSet, this class
// does not prevent further mutations to the underlying Fidl type. For well-
// defined behavior, the Fidl types should not be modified after being added to
// the set.
//
// Template parameters:
// * FidlType - the Fidl type governing each element of the collection, e.g.
// InterfacePtr, Binding, or StrongBinding
// * T - the element type of the collection
// * GetFidlType - a function that extracts the FidlType from an element of the
// collection. Defaults to the identity function, which only works if T =
// FidlType.
// * UniqueType - a type that uniquely identifies a FidlType in the collection.
// For InterfacePtrs, this is a pointer to the interface. For bindings, this is
// the pointer to the binding.
// * Identify - a function that derives a UniqueType from a FidlType. Defaults
// behave as described at UniqueType.
template <typename FidlType, typename T = FidlType,
FidlType* GetFidlType(T*) = GetFidlType, typename UniqueType = void*,
UniqueType Identify(FidlType*) = Identify>
class BoundSet {
public:
typedef typename std::vector<T>::iterator iterator;
BoundSet() {}
virtual ~BoundSet() {}
// |ptr| must be bound to a channel.
template <typename... _Args>
T* emplace(_Args&&... __args) {
elements_.emplace_back(std::forward<_Args>(__args)...);
T* const c = &elements_.back();
FidlType* const m = GetFidlType(c);
FXL_CHECK(m->is_bound());
UniqueType const id = Identify(m);
// Set the connection error handler for the newly added item to be a
// function that will erase it from the vector.
m->set_error_handler(
[this, id](zx_status_t status) { OnConnectionError(id); });
return c;
}
UniqueType GetId(T* object) { return Identify(GetFidlType(object)); }
// Removes the element at the given iterator. This effectively closes the pipe
// there if open, but it does not call OnConnectionError.
iterator erase(iterator it) { return elements_.erase(it); }
iterator erase(UniqueType id) {
auto it = Find(id);
FXL_CHECK(it != elements_.end());
return elements_.erase(it);
}
// Closes the Channel associated with each of the items in this set and
// clears the set. This does not call OnConnectionError for every interface in
// the set.
void clear() { elements_.clear(); }
bool empty() const { return elements_.empty(); }
size_t size() const { return elements_.size(); }
iterator begin() { return elements_.begin(); }
iterator end() { return elements_.end(); }
protected:
virtual void OnConnectionError(UniqueType id) { erase(id); }
private:
iterator Find(UniqueType id) {
return std::find_if(elements_.begin(), elements_.end(),
[id](T& e) { return Identify(GetFidlType(&e)) == id; });
}
std::vector<T> elements_;
};
// Convenience alias of BoundSet to handle non-movable FIDL types, like Bindings
// (and the mythical StrongBinding).
//
// Note that the default T here must be a unique_ptr rather than the FIDL type
// itself since these FIDL types are not movable.
template <typename FidlType, typename T = std::unique_ptr<FidlType>,
FidlType* GetFidlType(T*) = GetFidlType>
using BoundNonMovableSet = BoundSet<FidlType, T, GetFidlType, FidlType*>;
template <typename Interface,
typename T = std::unique_ptr<fidl::InterfacePtr<Interface>>,
fidl::InterfacePtr<Interface>* GetFidlType(T*) = GetFidlType>
using BoundPtrSet =
BoundNonMovableSet<fidl::InterfacePtr<Interface>, T, GetFidlType>;
// Convenience alias of BoundSet to handle Binding containers.
template <typename Interface,
typename T = std::unique_ptr<fidl::Binding<Interface>>,
fidl::Binding<Interface>* GetFidlType(T*) = GetFidlType>
using BindingSet = BoundNonMovableSet<fidl::Binding<Interface>, T, GetFidlType>;
} // namespace modular
#endif // PERIDOT_LIB_BOUND_SET_BOUND_SET_H_