blob: 7ea34380c509313ce86478e0373708d87e8421cd [file] [log] [blame]
// Copyright 2018 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_INTERFACE_PTR_SET_H_
#define LIB_FIDL_CPP_INTERFACE_PTR_SET_H_
#include <zircon/assert.h>
#include <vector>
#include "lib/fidl/cpp/interface_ptr.h"
namespace fidl {
// Contains a set of |InterfacePtr| objects, each with their own channels.
//
// An |InterfacePtr| is removed from the set and destroyed when its underlying
// channel experiences an error. When the set is destroyed, all the underlying
// channels are closed.
//
// An |InterfacePtrSet| is useful for broadcasting messages to a set of clients,
// each with their own implementation of |Interface|.
//
// See also:
//
// * |BindingSet|, which is the server analog of an |InterfacePtrSet|.
template <typename Interface>
class InterfacePtrSet final {
public:
using StorageType = std::vector<std::unique_ptr<InterfacePtr<Interface>>>;
using Ptr = InterfacePtr<Interface>;
// Creates an empty |InterfacePtrSet|.
InterfacePtrSet() = default;
InterfacePtrSet(const InterfacePtrSet& other) = delete;
InterfacePtrSet& operator=(const InterfacePtrSet& other) = delete;
// Adds the given |InterfacePtr| to the set.
//
// The |InterfacePtr| must already be bound to a channel. The |InterfacePtr|
// will be removed from the set when its underlying channel experiences an
// error.
void AddInterfacePtr(InterfacePtr<Interface> ptr) {
ZX_DEBUG_ASSERT(ptr.is_bound());
// Allocated a new |InterfacePtr| so that we can have a unique value to use
// as a key for removing the InterfacePtr. Otherwise, we'll lose track of
// the InterfacePtr when the vector resizes.
ptrs_.push_back(std::make_unique<Ptr>(std::move(ptr)));
auto* pointer = ptrs_.back().get();
pointer->set_error_handler(
[pointer, this](zx_status_t status) { this->RemoveOnError(pointer); });
}
// The |InterfacePtr| objects stored in this set.
//
// This collection of bindings can be invalidated when an |InterfacePtr| in
// the set encounters a connection error because connection errors causes the
// |InterfacePtrSet| to remove the |InterfacePtr| from the set.
const StorageType& ptrs() const { return ptrs_; }
// Closes all channels associated with |InterfacePtr| objects in the set.
//
// After this method returns, the set is empty.
void CloseAll() { ptrs_.clear(); }
// The number of |InterfacePtr| objects in the set.
//
// This number might be smaller than the number of |InterfacePtr| objects
// added to the set if some of the underlying channels have experienced an
// error.
size_t size() const { return ptrs_.size(); }
private:
// Removes the given |pointer| from the set.
//
// Called from the error handler callback for |pointer|.
void RemoveOnError(Ptr* pointer) {
auto it = std::find_if(ptrs_.begin(), ptrs_.end(),
[pointer](const std::unique_ptr<Ptr>& p) { return p.get() == pointer; });
ZX_DEBUG_ASSERT(it != ptrs_.end());
ptrs_.erase(it);
}
// We use |unique_ptr| rather than just |InterfacePtr| so that we can keep
// track of the |InterfacePtr| objects after the |vector| resizes and moves
// its contents to its new buffer.
StorageType ptrs_;
};
} // namespace fidl
#endif // LIB_FIDL_CPP_INTERFACE_PTR_SET_H_