Commit 12a26a1c authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[mojo-bindings] New associated endpoint types

Adds associated analogs for Remote, Receiver, ReceiverSet,
PendingRemote, and PendingReceiver. Basic smoke test coverage for
compile and basic operation, since implementation is in terms of types
with extensive coverage already.

Bug: 875030
Change-Id: Ib441f15da94e1c481e9f7f88d3012ceda886bbf3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1574365
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652664}
parent 9afb3710
......@@ -118,6 +118,9 @@ component("bindings") {
"associated_interface_ptr.h",
"associated_interface_ptr_info.h",
"associated_interface_request.h",
"associated_receiver.h",
"associated_receiver_set.h",
"associated_remote.h",
"binding.h",
"binding_set.h",
"callback_helpers.h",
......@@ -162,6 +165,8 @@ component("bindings") {
"lib/task_runner_helper.cc",
"lib/task_runner_helper.h",
"native_enum.h",
"pending_associated_receiver.h",
"pending_associated_remote.h",
"pending_receiver.h",
"pending_remote.h",
"pipe_control_message_handler.h",
......
// Copyright 2019 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_
#include <memory>
#include <utility>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/binding_state.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
// An AssociatedReceiver is used to receive and dispatch Interface method calls
// to a local implementation of Interface. Every AssociatedReceiver object is
// permanently linked to an implementation of Interface at construction time.
//
// Unlike Receiver, an AssociatedReceiver cannot immediately begin receiving
// messages from its entangled AssociatedRemote. One of the two endpoints must
// be transmitted across a concrete Remote first, at which point the endpoints
// begin piggybacking on that Remote's interface pipe.
template <typename Interface,
typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
class AssociatedReceiver {
public:
// Typically (and by default) an AssociatedReceiver uses a raw pointer to
// reference its linked Interface implementation object, because typically
// that implementation object owns the AssociatedReceiver. An alternative
// |ImplRefTraits| may be provided as a second AssociatedReceiver template
// argument in order to use a different reference type.
using ImplPointerType = typename ImplRefTraits::PointerType;
// Constructs an unbound AssociatedReceiver linked to |impl| for the duration
// of the AssociatedReceiver's lifetime. The AssociatedReceiver can be bound
// later by calling |Bind()| or |BindNewEndpointAndPassRemote()|. An unbound
// AssociatedReceiver does not schedule any asynchronous tasks.
explicit AssociatedReceiver(ImplPointerType impl)
: binding_(std::move(impl)) {}
// Constructs a bound AssociatedReceiver by consuming |pending_receiver|. The
// AssociatedReceiver is permanently linked to |impl| and will schedule
// incoming |impl| method and disconnection notifications on the default
// SequencedTaskRunner (i.e. base::SequencedTaskRunnerHandle::Get() at
// construction time).
AssociatedReceiver(ImplPointerType impl,
PendingAssociatedReceiver<Interface> pending_receiver)
: AssociatedReceiver(std::move(impl),
std::move(pending_receiver),
nullptr) {}
// Similar to above but the constructed AssociatedReceiver schedules all tasks
// via |task_runner| instead of the default SequencedTaskRunner. |task_runner|
// must run tasks on the same sequence that owns this AssociatedReceiver.
AssociatedReceiver(ImplPointerType impl,
PendingAssociatedReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: binding_(std::move(impl)) {
Bind(std::move(pending_receiver), std::move(task_runner));
}
~AssociatedReceiver() = default;
// Indicates whether this AssociatedReceiver is bound, meaning it may continue
// to receive Interface method calls from a remote caller.
//
// NOTE: An AssociatedReceiver is NEVER passively unbound. The only way for it
// to become unbound is to explicitly call |reset()| or |Unbind()|.
bool is_bound() const { return binding_.is_bound(); }
// Sets a OnceClosure to be invoked if this AssociatedReceiver is cut off from
// its AssociatedRemote (or PendingAssociatedRemote). This can happen if the
// corresponding AssociatedRemote (or unconsumed PendingAssociatedRemote) has
// been destroyed, or if the AssociatedRemote sends a malformed message. Must
// only be called on a bound AssociatedReceiver object, and only remains set
// as long as the AssociatedReceiver is both bound and connected.
//
// If ever invoked, |handler| will be scheduled asynchronously on the
// AssociatedReceiver's bound SequencedTaskRunner.
void set_disconnect_handler(base::OnceClosure handler) {
binding_.set_connection_error_handler(std::move(handler));
}
// Resets this AssociatedReceiver to an unbound state. An unbound
// AssociatedReceiver will NEVER schedule method calls or disconnection
// notifications, and any pending tasks which were scheduled prior to
// unbinding are effectively cancelled.
void reset() { binding_.Close(); }
// Binds this AssociatedReceiver, connecting it to a new
// PendingAssociatedRemote which is returned for transmission elsewhere
// (typically to an AssociatedRemote who will consume it to start making
// calls).
//
// The AssociatedReceiver will schedule incoming |impl| method calls and
// disconnection notifications on the default SequencedTaskRunner (i.e.
// base::SequencedTaskRunnerHandle::Get() at the time of this call). Must only
// be called on an unbound AssociatedReceiver.
PendingAssociatedRemote<Interface> BindNewEndpointAndPassRemote()
WARN_UNUSED_RESULT {
return BindNewEndpointAndPassRemote(nullptr);
}
// Like above, but the AssociatedReceiver will schedule incoming |impl| method
// calls and disconnection notifications on |task_runner| rather than on the
// default SequencedTaskRunner. Must only be called on an unbound
// AssociatedReceiver. |task_runner| must run tasks on the same sequence that
// owns this AssociatedReceiver.
PendingAssociatedRemote<Interface> BindNewEndpointAndPassRemote(
scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT {
DCHECK(!is_bound()) << "AssociatedReceiver is already bound";
PendingAssociatedRemote<Interface> remote;
Bind(remote.InitWithNewEndpointAndPassReceiver(), std::move(task_runner));
return remote;
}
// Binds this AssociatedReceiver by consuming |pending_receiver|. Must only be
// called on an unbound AssociatedReceiver.
//
// The newly bound AssociatedReceiver will schedule incoming |impl| method
// calls and disconnection notifications on the default SequencedTaskRunner
// (i.e. base::SequencedTaskRunnerHandle::Get() at the time of this call).
void Bind(PendingAssociatedReceiver<Interface> pending_receiver) {
Bind(std::move(pending_receiver), nullptr);
}
// Like above, but the newly bound AssociatedReceiver will schedule incoming
// |impl| method calls and disconnection notifications on |task_runner|
// instead of the default SequencedTaskRunner. Must only be called on an
// unbound AssociatedReceiver. |task_runner| must run tasks on the same
// sequence that owns this AssociatedReceiver.
void Bind(PendingAssociatedReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
if (pending_receiver) {
binding_.Bind(
AssociatedInterfaceRequest<Interface>(pending_receiver.PassHandle()),
std::move(task_runner));
} else {
reset();
}
}
// Unbinds this AssociatedReceiver, preventing any further |impl| method calls
// or disconnection notifications from being scheduled by it. Any such tasks
// that were scheduled prior to unbinding are effectively cancelled.
//
// Returns a PendingAssociatedReceiver which remains connected to this
// receiver's AssociatedRemote and which may be transferred elsewhere and
// consumed by another AssociatedReceiver. Any messages received but not
// actually dispatched by this AssociatedReceiver remain intact within the
// returned PendingAssociatedReceiver and can be dispatched by whomever binds
// with it later.
//
//
// Note that an AssociatedReceiver should not be unbound while there are still
// living response callbacks that haven't been invoked, as once the
// AssociatedReceiver is unbound those response callbacks are no longer valid
// and the AssociatedRemote will never be able to receive its expected
// responses.
PendingAssociatedReceiver<Interface> Unbind() WARN_UNUSED_RESULT {
return PendingAssociatedReceiver<Interface>(binding_.Unbind().PassHandle());
}
// Adds a message filter to be notified of each incoming message before
// dispatch. If a filter returns |false| from Accept(), the message is not
// dispatched and the pipe is closed. Filters cannot be removed once added.
void AddFilter(std::unique_ptr<MessageReceiver> filter) {
DCHECK(is_bound());
binding_.AddFilter(std::move(filter));
}
private:
// TODO(https://crbug.com/875030): Move AssociatedBinding details into this
// class.
AssociatedBinding<Interface, ImplRefTraits> binding_;
DISALLOW_COPY_AND_ASSIGN(AssociatedReceiver);
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_
// Copyright 2019 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_SET_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_SET_H_
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
namespace mojo {
template <typename Interface, typename ImplRefTraits>
struct ReceiverSetTraits<AssociatedReceiver<Interface, ImplRefTraits>> {
using InterfaceType = Interface;
using PendingType = PendingAssociatedReceiver<Interface>;
using ImplPointerType = typename ImplRefTraits::PointerType;
};
template <typename Interface, typename ContextType = void>
using AssociatedReceiverSet =
ReceiverSetBase<AssociatedReceiver<Interface>, ContextType>;
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_SET_H_
This diff is collapsed.
......@@ -16,6 +16,8 @@
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/handle.h"
......@@ -51,6 +53,33 @@ struct Serializer<AssociatedInterfacePtrInfoDataView<Base>,
}
};
template <typename Base, typename T>
struct Serializer<AssociatedInterfacePtrInfoDataView<Base>,
PendingAssociatedRemote<T>> {
static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
static void Serialize(PendingAssociatedRemote<T>& input,
AssociatedInterface_Data* output,
SerializationContext* context) {
DCHECK(!input.handle().is_valid() || input.handle().pending_association());
context->AddAssociatedInterfaceInfo(input.PassHandle(), input.version(),
output);
}
static bool Deserialize(AssociatedInterface_Data* input,
PendingAssociatedRemote<T>* output,
SerializationContext* context) {
auto handle = context->TakeAssociatedEndpointHandle(input->handle);
if (!handle.is_valid()) {
*output = PendingAssociatedRemote<T>();
} else {
output->set_handle(std::move(handle));
output->set_version(input->version);
}
return true;
}
};
template <typename Base, typename T>
struct Serializer<AssociatedInterfaceRequestDataView<Base>,
AssociatedInterfaceRequest<T>> {
......@@ -75,6 +104,30 @@ struct Serializer<AssociatedInterfaceRequestDataView<Base>,
}
};
template <typename Base, typename T>
struct Serializer<AssociatedInterfaceRequestDataView<Base>,
PendingAssociatedReceiver<T>> {
static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
static void Serialize(PendingAssociatedReceiver<T>& input,
AssociatedEndpointHandle_Data* output,
SerializationContext* context) {
DCHECK(!input.handle().is_valid() || input.handle().pending_association());
context->AddAssociatedEndpoint(input.PassHandle(), output);
}
static bool Deserialize(AssociatedEndpointHandle_Data* input,
PendingAssociatedReceiver<T>* output,
SerializationContext* context) {
auto handle = context->TakeAssociatedEndpointHandle(*input);
if (!handle.is_valid())
*output = PendingAssociatedReceiver<T>();
else
*output = PendingAssociatedReceiver<T>(std::move(handle));
return true;
}
};
template <typename Base, typename T>
struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
......
// Copyright 2019 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_RECEIVER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_RECEIVER_H_
#include <stdint.h>
#include <utility>
#include "base/macros.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
// PendingAssociatedReceiver represents an unbound associated interface
// endpoint that will receive and queue messages. An AssociatedReceiver can
// consume this object to begin receiving method calls from a corresponding
// AssociatedRemote.
template <typename Interface>
class PendingAssociatedReceiver {
public:
PendingAssociatedReceiver() = default;
PendingAssociatedReceiver(PendingAssociatedReceiver&& other)
: handle_(std::move(other.handle_)) {}
explicit PendingAssociatedReceiver(ScopedInterfaceEndpointHandle handle)
: handle_(std::move(handle)) {}
~PendingAssociatedReceiver() = default;
PendingAssociatedReceiver& operator=(PendingAssociatedReceiver&& other) {
handle_ = std::move(other.handle_);
return *this;
}
bool is_valid() const { return handle_.is_valid(); }
explicit operator bool() const { return is_valid(); }
ScopedInterfaceEndpointHandle PassHandle() { return std::move(handle_); }
const ScopedInterfaceEndpointHandle& handle() const { return handle_; }
void set_handle(ScopedInterfaceEndpointHandle handle) {
handle_ = std::move(handle);
}
private:
ScopedInterfaceEndpointHandle handle_;
DISALLOW_COPY_AND_ASSIGN(PendingAssociatedReceiver);
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_RECEIVER_H_
// Copyright 2019 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_REMOTE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_REMOTE_H_
#include <stdint.h>
#include <utility>
#include "base/macros.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
namespace mojo {
// PendingAssociatedRemote represents an unbound associated interface endpoint
// that will be used to send messages. An AssociatedRemote can consume this
// object to begin issuing method calls to a corresponding AssociatedReceiver.
template <typename Interface>
class PendingAssociatedRemote {
public:
PendingAssociatedRemote() = default;
PendingAssociatedRemote(PendingAssociatedRemote&& other)
: handle_(std::move(other.handle_)), version_(other.version_) {}
PendingAssociatedRemote(ScopedInterfaceEndpointHandle handle,
uint32_t version)
: handle_(std::move(handle)), version_(version) {}
~PendingAssociatedRemote() = default;
PendingAssociatedRemote& operator=(PendingAssociatedRemote&& other) {
handle_ = std::move(other.handle_);
version_ = other.version_;
return *this;
}
bool is_valid() const { return handle_.is_valid(); }
explicit operator bool() const { return is_valid(); }
ScopedInterfaceEndpointHandle PassHandle() { return std::move(handle_); }
const ScopedInterfaceEndpointHandle& handle() const { return handle_; }
void set_handle(ScopedInterfaceEndpointHandle handle) {
handle_ = std::move(handle);
}
uint32_t version() const { return version_; }
void set_version(uint32_t version) { version_ = version; }
PendingAssociatedReceiver<Interface> InitWithNewEndpointAndPassReceiver() {
ScopedInterfaceEndpointHandle receiver_handle;
ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(
&handle_, &receiver_handle);
set_version(0);
return PendingAssociatedReceiver<Interface>(std::move(receiver_handle));
}
private:
ScopedInterfaceEndpointHandle handle_;
uint32_t version_ = 0;
DISALLOW_COPY_AND_ASSIGN(PendingAssociatedRemote);
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_PENDING_ASSOCIATED_REMOTE_H_
......@@ -31,6 +31,7 @@ struct ReceiverSetTraits;
template <typename Interface, typename ImplRefTraits>
struct ReceiverSetTraits<Receiver<Interface, ImplRefTraits>> {
using InterfaceType = Interface;
using PendingType = PendingReceiver<Interface>;
using ImplPointerType = typename ImplRefTraits::PointerType;
};
......@@ -87,6 +88,7 @@ class ReceiverSetBase {
public:
using Traits = ReceiverSetTraits<ReceiverType>;
using Interface = typename Traits::InterfaceType;
using PendingType = typename Traits::PendingType;
using ImplPointerType = typename Traits::ImplPointerType;
using ContextTraits = ReceiverSetContextTraits<ContextType>;
using Context = typename ContextTraits::Type;
......@@ -112,7 +114,7 @@ class ReceiverSetBase {
// will be used to run scheduled tasks for the receiver.
ReceiverId Add(
ImplPointerType impl,
PendingReceiver<Interface> receiver,
PendingType receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
static_assert(!ContextTraits::SupportsContext(),
"Context value required for non-void context type.");
......@@ -124,7 +126,7 @@ class ReceiverSetBase {
// other (identical) details.
ReceiverId Add(
ImplPointerType impl,
PendingReceiver<Interface> receiver,
PendingType receiver,
Context context,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
static_assert(ContextTraits::SupportsContext(),
......@@ -226,7 +228,7 @@ class ReceiverSetBase {
class Entry {
public:
Entry(ImplPointerType impl,
PendingReceiver<Interface> receiver,
PendingType receiver,
ReceiverSetBase* receiver_set,
ReceiverId receiver_id,
Context context,
......@@ -283,7 +285,7 @@ class ReceiverSetBase {
}
ReceiverId AddImpl(ImplPointerType impl,
PendingReceiver<Interface> receiver,
PendingType receiver,
Context context,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
ReceiverId id = next_receiver_id_++;
......
......@@ -231,6 +231,12 @@ class Remote {
return PendingRemote<Interface>(info.PassHandle(), info.version());
}
// Sends a no-op message on the underlying message pipe and runs the current
// message loop until its response is received. This can be used in tests to
// verify that no message was sent on a message pipe in response to some
// stimulus.
void FlushForTesting() { internal_state_.FlushForTesting(); }
// DO NOT USE. Exposed only for internal use and for testing.
internal::InterfacePtrState<Interface>* internal_state() {
return &internal_state_;
......
......@@ -8,11 +8,15 @@
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
......@@ -121,6 +125,55 @@ class ObserverImpl : public mojom::WidgetObserver {
DISALLOW_COPY_AND_ASSIGN(ObserverImpl);
};
class PingerImpl : public mojom::Pinger {
public:
PingerImpl() = default;
~PingerImpl() override = default;
int ping_count() const { return ping_count_; }
void AddReceiver(mojo::PendingAssociatedReceiver<mojom::Pinger> receiver) {
receivers_.Add(this, std::move(receiver));
}
private:
// mojom::Ping:
void Ping(PingCallback callback) override {
++ping_count_;
std::move(callback).Run();
}
mojo::AssociatedReceiverSet<mojom::Pinger> receivers_;
int ping_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(PingerImpl);
};
class AssociatedPingerHostImpl : public mojom::AssociatedPingerHost {
public:
explicit AssociatedPingerHostImpl(
mojo::PendingReceiver<mojom::AssociatedPingerHost> receiver)
: receiver_(this, std::move(receiver)) {}
~AssociatedPingerHostImpl() override = default;
int ping_count() const { return pinger_.ping_count(); }
private:
// mojom::AssociatedPingerHost:
void AddEndpoints(
mojo::PendingAssociatedReceiver<mojom::Pinger> receiver,
mojo::PendingAssociatedRemote<mojom::Pinger> remote) override {
mojo::AssociatedRemote<mojom::Pinger> pinger(std::move(remote));
pinger->Ping(base::DoNothing());
pinger_.AddReceiver(std::move(receiver));
}
mojo::Receiver<mojom::AssociatedPingerHost> receiver_;
PingerImpl pinger_;
DISALLOW_COPY_AND_ASSIGN(AssociatedPingerHostImpl);
};
TEST(NewEndpointTypesTest, BasicUsage) {
// A simple smoke/compile test for new bindings endpoint types. Used to
// demonstrate look & feel as well as to ensure basic completeness and
......@@ -209,6 +262,44 @@ TEST(NewEndpointTypesTest, BasicUsage) {
observer2.WaitForDisconnect();
}
TEST(NewEndpointTypesTest, AssociatedTypes) {
base::test::ScopedTaskEnvironment task_environment;
mojo::Remote<mojom::AssociatedPingerHost> host;
AssociatedPingerHostImpl host_impl(host.BindNewPipeAndPassReceiver());
PingerImpl test_pinger_impl;
mojo::PendingAssociatedRemote<mojom::Pinger> test_pinger1;
mojo::PendingAssociatedRemote<mojom::Pinger> test_pinger2;
test_pinger_impl.AddReceiver(
test_pinger1.InitWithNewEndpointAndPassReceiver());
test_pinger_impl.AddReceiver(
test_pinger2.InitWithNewEndpointAndPassReceiver());
mojo::AssociatedRemote<mojom::Pinger> host_pinger1;
mojo::AssociatedRemote<mojom::Pinger> host_pinger2;
// Both of these calls should result in a single ping each to |pinger_impl|.
host->AddEndpoints(host_pinger1.BindNewEndpointAndPassReceiver(),
std::move(test_pinger1));
host->AddEndpoints(host_pinger2.BindNewEndpointAndPassReceiver(),
std::move(test_pinger2));
// Ping each host pinger twice, should result in a total of 4 pings to
// |host|'s PingerImpl.
host_pinger1->Ping(base::DoNothing());
host_pinger1->Ping(base::DoNothing());
host_pinger2->Ping(base::DoNothing());
host_pinger2->Ping(base::DoNothing());
// Should be sufficient to flush all interesting operations, since they all
// run on the same pipe.
host.FlushForTesting();
EXPECT_EQ(4, host_impl.ping_count());
EXPECT_EQ(2, test_pinger_impl.ping_count());
}
} // namespace new_endpoint_types
} // namespace test
} // namespace mojo
......@@ -22,3 +22,12 @@ interface WidgetFactory {
CreateWidget(pending_receiver<Widget> receiver,
pending_remote<WidgetClient> client);
};
interface Pinger {
Ping() => ();
};
interface AssociatedPingerHost {
AddEndpoints(pending_associated_receiver<Pinger> receiver,
pending_associated_remote<Pinger> remote);
};
......@@ -48,6 +48,8 @@ namespace {{variant}} {
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
......
......@@ -595,6 +595,12 @@ class Generator(generator.Generator):
if mojom.IsPendingReceiverKind(kind):
return "mojo::PendingReceiver<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingAssociatedRemoteKind(kind):
return "mojo::PendingAssociatedRemote<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsPendingAssociatedReceiverKind(kind):
return "mojo::PendingAssociatedReceiver<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfo" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
......@@ -685,9 +691,11 @@ class Generator(generator.Generator):
return "mojo::internal::Interface_Data"
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo::internal::Handle_Data"
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "mojo::internal::AssociatedInterface_Data"
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo::internal::AssociatedEndpointHandle_Data"
if mojom.IsEnumKind(kind):
return "int32_t"
......@@ -905,9 +913,11 @@ class Generator(generator.Generator):
if mojom.IsPendingReceiverKind(kind):
return ("mojo::InterfaceRequestDataView<%sInterfaceBase>" %
_GetName(kind.kind))
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "%sAssociatedRequestDataView" % _GetName(kind.kind)
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
......
......@@ -221,9 +221,11 @@ def DecodeMethod(context, kind, offset, bit):
return 'readInterfaceRequest'
if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
return 'readServiceInterface'
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return 'readAssociatedInterfaceRequestNotSupported'
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return 'readAssociatedServiceInterfaceNotSupported'
return _spec_to_decode_method[kind.spec]
methodName = _DecodeMethodName(kind)
......@@ -282,9 +284,11 @@ def GetJavaType(context, kind, boxed=False, with_generics=True):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' %
GetNameForKind(context, kind.kind))
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return 'org.chromium.mojo.bindings.AssociatedInterfaceNotSupported'
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return 'org.chromium.mojo.bindings.AssociatedInterfaceRequestNotSupported'
if mojom.IsMapKind(kind):
if with_generics:
......@@ -425,7 +429,8 @@ def TempDir():
def EnumCoversContinuousRange(kind):
if not kind.fields:
return False
number_of_unique_keys = len(set(map(lambda field: field.numeric_value, kind.fields)))
number_of_unique_keys = len(set(map(
lambda field: field.numeric_value, kind.fields)))
if kind.max_value - kind.min_value + 1 != number_of_unique_keys:
return False
return True
......
......@@ -401,10 +401,12 @@ class Generator(generator.Generator):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo.InterfaceRequest"
# TODO(calamity): Support associated interfaces properly.
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "mojo.AssociatedInterfacePtrInfo"
# TODO(calamity): Support associated interface requests properly.
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo.AssociatedInterfaceRequest"
# TODO(calamity): Support enums properly.
......@@ -459,10 +461,12 @@ class Generator(generator.Generator):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return name + "Request"
# TODO(calamity): Support associated interfaces properly.
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "Object"
# TODO(calamity): Support associated interface requests properly.
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "Object"
raise Exception("No valid closure type: %s" % kind)
......@@ -553,11 +557,13 @@ class Generator(generator.Generator):
return "mojo.internal.InterfaceProxy(%sProxy)" % name
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo.internal.InterfaceRequest(%sRequest)" % name
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
# TODO(rockot): Implement associated interfaces.
return "mojo.internal.AssociatedInterfaceProxy(%sProxy)" % (
name)
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo.internal.AssociatedInterfaceRequest(%s)" % name
return name
......@@ -594,9 +600,11 @@ class Generator(generator.Generator):
if (mojom.IsInterfaceRequestKind(field.kind) or
mojom.IsPendingReceiverKind(field.kind)):
return "new bindings.InterfaceRequest()"
if mojom.IsAssociatedInterfaceKind(field.kind):
if (mojom.IsAssociatedInterfaceKind(field.kind) or
mojom.IsPendingAssociatedRemoteKind(field.kind)):
return "new associatedBindings.AssociatedInterfacePtrInfo()"
if mojom.IsAssociatedInterfaceRequestKind(field.kind):
if (mojom.IsAssociatedInterfaceRequestKind(field.kind) or
mojom.IsPendingAssociatedReceiverKind(field.kind)):
return "new associatedBindings.AssociatedInterfaceRequest()"
if mojom.IsEnumKind(field.kind):
return "0"
......@@ -641,10 +649,12 @@ class Generator(generator.Generator):
return "codec.%s" % (
"NullableInterfaceRequest" if mojom.IsNullableKind(kind)
else "InterfaceRequest")
if mojom.IsAssociatedInterfaceKind(kind):
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "codec.%s" % ("NullableAssociatedInterfacePtrInfo"
if mojom.IsNullableKind(kind) else "AssociatedInterfacePtrInfo")
if mojom.IsAssociatedInterfaceRequestKind(kind):
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "codec.%s" % ("NullableAssociatedInterfaceRequest"
if mojom.IsNullableKind(kind) else "AssociatedInterfaceRequest")
if mojom.IsEnumKind(kind):
......@@ -812,10 +822,12 @@ class Generator(generator.Generator):
elif mojom.IsPendingRemoteKind(kind):
return '{0}.{1}Ptr'.format(kind.kind.module.namespace,
kind.kind.name)
elif mojom.IsAssociatedInterfaceRequestKind(kind):
elif (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace,
kind.kind.name)
elif mojom.IsAssociatedInterfaceKind(kind):
elif (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return '{0}.{1}AssociatedPtr'.format(kind.kind.module.namespace,
kind.kind.name)
elif mojom.IsSharedBufferKind(kind):
......
......@@ -520,6 +520,36 @@ class PendingReceiver(ReferenceKind):
self.kind = kind
class PendingAssociatedRemote(ReferenceKind):
ReferenceKind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
if not isinstance(kind, Interface):
raise Exception(
'pending_associated_remote<T> requires T to be an interface ' +
'type. Got %r' % kind.spec)
ReferenceKind.__init__(self, 'rma:' + kind.spec)
else:
ReferenceKind.__init__(self)
self.kind = kind
class PendingAssociatedReceiver(ReferenceKind):
ReferenceKind.AddSharedProperty('kind')
def __init__(self, kind=None):
if kind is not None:
if not isinstance(kind, Interface):
raise Exception(
'pending_associated_receiver<T> requires T to be an interface' +
'type. Got %r' % kind.spec)
ReferenceKind.__init__(self, 'rca:' + kind.spec)
else:
ReferenceKind.__init__(self)
self.kind = kind
class InterfaceRequest(ReferenceKind):
ReferenceKind.AddSharedProperty('kind')
......@@ -877,6 +907,14 @@ def IsPendingReceiverKind(kind):
return isinstance(kind, PendingReceiver)
def IsPendingAssociatedRemoteKind(kind):
return isinstance(kind, PendingAssociatedRemote)
def IsPendingAssociatedReceiverKind(kind):
return isinstance(kind, PendingAssociatedReceiver)
def IsEnumKind(kind):
return isinstance(kind, Enum)
......@@ -923,7 +961,9 @@ def IsAnyHandleOrInterfaceKind(kind):
def IsAssociatedKind(kind):
return (IsAssociatedInterfaceKind(kind) or
IsAssociatedInterfaceRequestKind(kind))
IsAssociatedInterfaceRequestKind(kind) or
IsPendingAssociatedRemoteKind(kind) or
IsPendingAssociatedReceiverKind(kind))
def HasCallbacks(interface):
......
......@@ -45,13 +45,14 @@ class PackedField(object):
def GetSizeForKind(cls, kind):
if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct,
mojom.Interface, mojom.AssociatedInterface,
mojom.PendingRemote)):
mojom.PendingRemote, mojom.PendingAssociatedRemote)):
return 8
if isinstance(kind, mojom.Union):
return 16
if isinstance(kind, (mojom.InterfaceRequest, mojom.PendingReceiver)):
kind = mojom.MSGPIPE
if isinstance(kind, mojom.AssociatedInterfaceRequest):
if isinstance(kind, (mojom.AssociatedInterfaceRequest,
mojom.PendingAssociatedReceiver)):
return 4
if isinstance(kind, mojom.Enum):
# TODO(mpcomplete): what about big enums?
......
......@@ -70,7 +70,8 @@ def _MapKind(kind):
base_kind = _MapKind(kind[0:-1])
# NOTE: This doesn't rule out enum types. Those will be detected later, when
# cross-reference is established.
reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso', 'rmt', 'rcv')
reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso', 'rmt', 'rcv',
'rma', 'rca')
if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds:
raise Exception(
'A type (spec "%s") cannot be made nullable' % base_kind)
......@@ -94,6 +95,12 @@ def _MapKind(kind):
if kind.startswith('rcv<'):
assert kind.endswith('>')
return 'rcv:' + _MapKind(kind[4:-1])
if kind.startswith('rma<'):
assert kind.endswith('>')
return 'rma:' + _MapKind(kind[4:-1])
if kind.startswith('rca<'):
assert kind.endswith('>')
return 'rca:' + _MapKind(kind[4:-1])
if kind in map_to_kind:
return map_to_kind[kind]
return 'x:' + kind
......@@ -213,6 +220,10 @@ def _Kind(kinds, spec, scope):
kind = mojom.PendingRemote(_Kind(kinds, spec[4:], scope))
elif spec.startswith('rcv:'):
kind = mojom.PendingReceiver(_Kind(kinds, spec[4:], scope))
elif spec.startswith('rma:'):
kind = mojom.PendingAssociatedRemote(_Kind(kinds, spec[4:], scope))
elif spec.startswith('rca:'):
kind = mojom.PendingAssociatedReceiver(_Kind(kinds, spec[4:], scope))
elif spec.startswith('m['):
# Isolate the two types from their brackets.
......
......@@ -67,7 +67,9 @@ class Lexer(object):
'MAP',
'ASSOCIATED',
'PENDING_REMOTE',
'PENDING_RECEIVER'
'PENDING_RECEIVER',
'PENDING_ASSOCIATED_REMOTE',
'PENDING_ASSOCIATED_RECEIVER',
)
keyword_map = {}
......
......@@ -273,6 +273,8 @@ class Parser(object):
def p_basictypename(self, p):
"""basictypename : remotetype
| receivertype
| associatedremotetype
| associatedreceivertype
| identifier
| ASSOCIATED identifier
| handletype"""
......@@ -289,6 +291,16 @@ class Parser(object):
"""receivertype : PENDING_RECEIVER LANGLE identifier RANGLE"""
p[0] = "rcv<%s>" % p[3]
def p_associatedremotetype(self, p):
"""associatedremotetype : PENDING_ASSOCIATED_REMOTE LANGLE identifier \
RANGLE"""
p[0] = "rma<%s>" % p[3]
def p_associatedreceivertype(self, p):
"""associatedreceivertype : PENDING_ASSOCIATED_RECEIVER LANGLE identifier \
RANGLE"""
p[0] = "rca<%s>" % p[3]
def p_handletype(self, p):
"""handletype : HANDLE
| HANDLE LANGLE NAME RANGLE"""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment