#ifndef MOJO_PUBLIC_CPP_BINDINGS_SHARED_REMOTE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_SHARED_REMOTE_H_
#include <memory>
#include <tuple>
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/sequenced_task_runner_helpers.h"
#include "base/task/task_runner.h"
#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/lib/thread_safe_forwarder_base.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/runtime_features.h"
namespace mojo {
namespace internal {
template <typename RemoteType>
struct SharedRemoteTraits;
template <typename Interface>
struct SharedRemoteTraits<Remote<Interface>> {
static void BindDisconnected(Remote<Interface>& remote) {
std::ignore = remote.BindNewPipeAndPassReceiver();
}
};
}
template <typename Interface>
class ThreadSafeForwarder : public internal::ThreadSafeForwarderBase {
public:
using ProxyType = typename Interface::Proxy_;
explicit ThreadSafeForwarder(scoped_refptr<ThreadSafeProxy> thread_safe_proxy)
: ThreadSafeForwarderBase(std::move(thread_safe_proxy)), proxy_(this) {}
ThreadSafeForwarder(const ThreadSafeForwarder&) = delete;
ThreadSafeForwarder& operator=(const ThreadSafeForwarder&) = delete;
~ThreadSafeForwarder() override = default;
ProxyType& proxy() { return proxy_; }
private:
ProxyType proxy_;
};
template <typename Interface>
class SharedRemote;
template <typename RemoteType>
class SharedRemoteBase
: public base::RefCountedThreadSafe<SharedRemoteBase<RemoteType>> {
public:
using InterfaceType = typename RemoteType::InterfaceType;
using PendingType = typename RemoteType::PendingType;
SharedRemoteBase(const SharedRemoteBase&) = delete;
SharedRemoteBase& operator=(const SharedRemoteBase&) = delete;
InterfaceType* get() { return &forwarder_->proxy(); }
InterfaceType* operator->() { return get(); }
InterfaceType& operator*() { return *get(); }
void set_disconnect_handler(
base::OnceClosure handler,
scoped_refptr<base::SequencedTaskRunner> handler_task_runner) {
wrapper_->set_disconnect_handler(std::move(handler),
std::move(handler_task_runner));
}
void Disconnect() { wrapper_->Disconnect(); }
private:
friend class base::RefCountedThreadSafe<SharedRemoteBase<RemoteType>>;
template <typename Interface>
friend class SharedRemote;
template <typename Interface>
friend class SharedAssociatedRemote;
struct RemoteWrapperDeleter;
class RemoteWrapper
: public base::RefCountedThreadSafe<RemoteWrapper, RemoteWrapperDeleter> {
public:
RemoteWrapper(PendingType remote,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(std::move(task_runner)),
remote_(std::move(remote), task_runner_),
associated_group_(*remote_.internal_state()->associated_group()) {}
RemoteWrapper(const RemoteWrapper&) = delete;
RemoteWrapper& operator=(const RemoteWrapper&) = delete;
std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder(
const base::Location& location) {
return std::make_unique<ThreadSafeForwarder<InterfaceType>>(
remote_.internal_state()->CreateThreadSafeProxy(
base::MakeRefCounted<ProxyTarget>(this), location));
}
void set_disconnect_handler(
base::OnceClosure handler,
scoped_refptr<base::SequencedTaskRunner> handler_task_runner) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&RemoteWrapper::set_disconnect_handler, this,
std::move(handler), std::move(handler_task_runner)));
return;
}
auto wrapped_handler =
base::BindOnce(base::IgnoreResult(&base::TaskRunner::PostTask),
handler_task_runner, FROM_HERE, std::move(handler));
if (!remote_.is_connected()) {
std::move(wrapped_handler).Run();
return;
}
remote_.set_disconnect_handler(std::move(wrapped_handler));
}
void Disconnect() {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&RemoteWrapper::Disconnect, this));
return;
}
remote_.reset();
internal::SharedRemoteTraits<RemoteType>::BindDisconnected(remote_);
}
private:
friend struct RemoteWrapperDeleter;
friend class base::DeleteHelper<RemoteWrapper>;
~RemoteWrapper() = default;
class ProxyTarget : public ThreadSafeProxy::Target {
public:
explicit ProxyTarget(scoped_refptr<RemoteWrapper> wrapper)
: wrapper_(std::move(wrapper)) {}
private:
~ProxyTarget() override = default;
const scoped_refptr<RemoteWrapper> wrapper_;
};
void DeleteOnCorrectThread() const {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->DeleteSoon(FROM_HERE, this);
} else {
delete this;
}
}
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
RemoteType remote_;
AssociatedGroup associated_group_;
};
struct RemoteWrapperDeleter {
static void Destruct(const RemoteWrapper* wrapper) {
wrapper->DeleteOnCorrectThread();
}
};
explicit SharedRemoteBase(scoped_refptr<RemoteWrapper> wrapper,
const base::Location& location)
: wrapper_(std::move(wrapper)),
forwarder_(wrapper_->CreateForwarder(location)) {}
static scoped_refptr<SharedRemoteBase> Create(
PendingType pending_remote,
scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::Location& location) {
return new SharedRemoteBase(
base::MakeRefCounted<RemoteWrapper>(std::move(pending_remote),
std::move(task_runner)),
location);
}
~SharedRemoteBase() = default;
const scoped_refptr<RemoteWrapper> wrapper_;
const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_;
};
template <typename Interface>
class SharedRemote {
public:
SharedRemote() = default;
explicit SharedRemote(
PendingRemote<Interface> pending_remote,
const base::Location& location = base::Location::Current()) {
Bind(std::move(pending_remote), nullptr, location);
}
SharedRemote(PendingRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> bind_task_runner,
const base::Location& location = base::Location::Current()) {
Bind(std::move(pending_remote), std::move(bind_task_runner), location);
}
SharedRemote(const SharedRemote&) = default;
SharedRemote(SharedRemote&&) = default;
SharedRemote& operator=(const SharedRemote&) = default;
SharedRemote& operator=(SharedRemote&&) = default;
bool is_bound() const { return remote_ != nullptr; }
explicit operator bool() const { return is_bound(); }
Interface* get() const { return remote_->get(); }
Interface* operator->() const { return get(); }
Interface& operator*() const { return *get(); }
void set_disconnect_handler(
base::OnceClosure handler,
scoped_refptr<base::SequencedTaskRunner> handler_task_runner) {
remote_->set_disconnect_handler(std::move(handler),
std::move(handler_task_runner));
}
void reset() { remote_.reset(); }
void Disconnect() { remote_->Disconnect(); }
void Bind(PendingRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> bind_task_runner,
const base::Location& location = base::Location::Current()) {
if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
remote_.reset();
return;
}
if (bind_task_runner && pending_remote) {
remote_ = SharedRemoteBase<Remote<Interface>>::Create(
std::move(pending_remote), std::move(bind_task_runner), location);
} else if (pending_remote) {
remote_ = SharedRemoteBase<Remote<Interface>>::Create(
std::move(pending_remote),
base::SequencedTaskRunner::GetCurrentDefault(), location);
}
}
PendingReceiver<Interface> BindNewPipeAndPassReceiver(
scoped_refptr<base::SequencedTaskRunner> bind_task_runner = nullptr,
const base::Location& location = base::Location::Current()) {
if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
return PendingReceiver<Interface>();
}
PendingRemote<Interface> remote;
auto receiver = remote.InitWithNewPipeAndPassReceiver();
Bind(std::move(remote), std::move(bind_task_runner), location);
return receiver;
}
private:
scoped_refptr<SharedRemoteBase<Remote<Interface>>> remote_;
};
}
#endif