#ifndef MEDIA_MOJO_SERVICES_DEFERRED_DESTROY_UNIQUE_RECEIVER_SET_H_
#define MEDIA_MOJO_SERVICES_DEFERRED_DESTROY_UNIQUE_RECEIVER_SET_H_
#include <stdint.h>
#include <map>
#include <memory>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/task/bind_post_task.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
namespace media {
template <typename Interface>
class DeferredDestroy : public Interface {
public:
virtual void OnDestroyPending(base::OnceClosure destroy_cb) = 0;
};
template <typename Interface>
class DeferredDestroyUniqueReceiverSet {
public:
class Deleter {
public:
using DeleteCallback =
base::RepeatingCallback<void(std::unique_ptr<Interface>)>;
Deleter() = default;
explicit Deleter(DeleteCallback delete_cb)
: delete_cb_(std::move(delete_cb)) {}
void operator()(Interface* p) {
auto ptr = base::WrapUnique<Interface>(p);
if (delete_cb_ && !delete_cb_.IsCancelled())
delete_cb_.Run(std::move(ptr));
else
ptr.reset();
}
private:
DeleteCallback delete_cb_;
};
DeferredDestroyUniqueReceiverSet() {}
DeferredDestroyUniqueReceiverSet(const DeferredDestroyUniqueReceiverSet&) =
delete;
DeferredDestroyUniqueReceiverSet& operator=(
const DeferredDestroyUniqueReceiverSet&) = delete;
void Add(std::unique_ptr<DeferredDestroy<Interface>> impl,
mojo::PendingReceiver<Interface> receiver) {
Deleter deleter(base::BindRepeating(
&DeferredDestroyUniqueReceiverSet::OnReceiverRemoved,
weak_factory_.GetWeakPtr()));
std::unique_ptr<Interface, Deleter> impl_with_deleter(impl.release(),
deleter);
receivers_.Add(std::move(impl_with_deleter), std::move(receiver));
}
void CloseAllReceivers() {
weak_factory_.InvalidateWeakPtrs();
receivers_.Clear();
unbound_impls_.clear();
}
bool empty() const { return receivers_.empty(); }
size_t size() const { return receivers_.size(); }
size_t unbound_size() const { return unbound_impls_.size(); }
private:
void OnReceiverRemoved(std::unique_ptr<Interface> ptr) {
DVLOG(1) << __func__;
id_++;
auto* impl_ptr = static_cast<DeferredDestroy<Interface>*>(ptr.get());
unbound_impls_[id_] = std::move(ptr);
impl_ptr->OnDestroyPending(base::BindPostTaskToCurrentDefault(
base::BindOnce(&DeferredDestroyUniqueReceiverSet::OnDestroyable,
weak_factory_.GetWeakPtr(), id_)));
}
void OnDestroyable(int id) {
DVLOG(1) << __func__;
unbound_impls_.erase(id);
}
uint32_t id_ = 0;
std::map<uint32_t, std::unique_ptr<Interface>> unbound_impls_;
mojo::UniqueReceiverSet<Interface, void, Deleter> receivers_;
base::WeakPtrFactory<DeferredDestroyUniqueReceiverSet> weak_factory_{this};
};
}
#endif