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") { ...@@ -118,6 +118,9 @@ component("bindings") {
"associated_interface_ptr.h", "associated_interface_ptr.h",
"associated_interface_ptr_info.h", "associated_interface_ptr_info.h",
"associated_interface_request.h", "associated_interface_request.h",
"associated_receiver.h",
"associated_receiver_set.h",
"associated_remote.h",
"binding.h", "binding.h",
"binding_set.h", "binding_set.h",
"callback_helpers.h", "callback_helpers.h",
...@@ -162,6 +165,8 @@ component("bindings") { ...@@ -162,6 +165,8 @@ component("bindings") {
"lib/task_runner_helper.cc", "lib/task_runner_helper.cc",
"lib/task_runner_helper.h", "lib/task_runner_helper.h",
"native_enum.h", "native_enum.h",
"pending_associated_receiver.h",
"pending_associated_remote.h",
"pending_receiver.h", "pending_receiver.h",
"pending_remote.h", "pending_remote.h",
"pipe_control_message_handler.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 @@ ...@@ -16,6 +16,8 @@
#include "mojo/public/cpp/bindings/lib/bindings_internal.h" #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_context.h"
#include "mojo/public/cpp/bindings/lib/serialization_forward.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_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/handle.h" #include "mojo/public/cpp/system/handle.h"
...@@ -51,6 +53,33 @@ struct Serializer<AssociatedInterfacePtrInfoDataView<Base>, ...@@ -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> template <typename Base, typename T>
struct Serializer<AssociatedInterfaceRequestDataView<Base>, struct Serializer<AssociatedInterfaceRequestDataView<Base>,
AssociatedInterfaceRequest<T>> { AssociatedInterfaceRequest<T>> {
...@@ -75,6 +104,30 @@ struct Serializer<AssociatedInterfaceRequestDataView<Base>, ...@@ -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> template <typename Base, typename T>
struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> { struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch."); 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; ...@@ -31,6 +31,7 @@ struct ReceiverSetTraits;
template <typename Interface, typename ImplRefTraits> template <typename Interface, typename ImplRefTraits>
struct ReceiverSetTraits<Receiver<Interface, ImplRefTraits>> { struct ReceiverSetTraits<Receiver<Interface, ImplRefTraits>> {
using InterfaceType = Interface; using InterfaceType = Interface;
using PendingType = PendingReceiver<Interface>;
using ImplPointerType = typename ImplRefTraits::PointerType; using ImplPointerType = typename ImplRefTraits::PointerType;
}; };
...@@ -87,6 +88,7 @@ class ReceiverSetBase { ...@@ -87,6 +88,7 @@ class ReceiverSetBase {
public: public:
using Traits = ReceiverSetTraits<ReceiverType>; using Traits = ReceiverSetTraits<ReceiverType>;
using Interface = typename Traits::InterfaceType; using Interface = typename Traits::InterfaceType;
using PendingType = typename Traits::PendingType;
using ImplPointerType = typename Traits::ImplPointerType; using ImplPointerType = typename Traits::ImplPointerType;
using ContextTraits = ReceiverSetContextTraits<ContextType>; using ContextTraits = ReceiverSetContextTraits<ContextType>;
using Context = typename ContextTraits::Type; using Context = typename ContextTraits::Type;
...@@ -112,7 +114,7 @@ class ReceiverSetBase { ...@@ -112,7 +114,7 @@ class ReceiverSetBase {
// will be used to run scheduled tasks for the receiver. // will be used to run scheduled tasks for the receiver.
ReceiverId Add( ReceiverId Add(
ImplPointerType impl, ImplPointerType impl,
PendingReceiver<Interface> receiver, PendingType receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) { scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
static_assert(!ContextTraits::SupportsContext(), static_assert(!ContextTraits::SupportsContext(),
"Context value required for non-void context type."); "Context value required for non-void context type.");
...@@ -124,7 +126,7 @@ class ReceiverSetBase { ...@@ -124,7 +126,7 @@ class ReceiverSetBase {
// other (identical) details. // other (identical) details.
ReceiverId Add( ReceiverId Add(
ImplPointerType impl, ImplPointerType impl,
PendingReceiver<Interface> receiver, PendingType receiver,
Context context, Context context,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) { scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
static_assert(ContextTraits::SupportsContext(), static_assert(ContextTraits::SupportsContext(),
...@@ -226,7 +228,7 @@ class ReceiverSetBase { ...@@ -226,7 +228,7 @@ class ReceiverSetBase {
class Entry { class Entry {
public: public:
Entry(ImplPointerType impl, Entry(ImplPointerType impl,
PendingReceiver<Interface> receiver, PendingType receiver,
ReceiverSetBase* receiver_set, ReceiverSetBase* receiver_set,
ReceiverId receiver_id, ReceiverId receiver_id,
Context context, Context context,
...@@ -283,7 +285,7 @@ class ReceiverSetBase { ...@@ -283,7 +285,7 @@ class ReceiverSetBase {
} }
ReceiverId AddImpl(ImplPointerType impl, ReceiverId AddImpl(ImplPointerType impl,
PendingReceiver<Interface> receiver, PendingType receiver,
Context context, Context context,
scoped_refptr<base::SequencedTaskRunner> task_runner) { scoped_refptr<base::SequencedTaskRunner> task_runner) {
ReceiverId id = next_receiver_id_++; ReceiverId id = next_receiver_id_++;
......
...@@ -231,6 +231,12 @@ class Remote { ...@@ -231,6 +231,12 @@ class Remote {
return PendingRemote<Interface>(info.PassHandle(), info.version()); 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. // DO NOT USE. Exposed only for internal use and for testing.
internal::InterfacePtrState<Interface>* internal_state() { internal::InterfacePtrState<Interface>* internal_state() {
return &internal_state_; return &internal_state_;
......
...@@ -8,11 +8,15 @@ ...@@ -8,11 +8,15 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_task_environment.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.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
...@@ -121,6 +125,55 @@ class ObserverImpl : public mojom::WidgetObserver { ...@@ -121,6 +125,55 @@ class ObserverImpl : public mojom::WidgetObserver {
DISALLOW_COPY_AND_ASSIGN(ObserverImpl); 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) { TEST(NewEndpointTypesTest, BasicUsage) {
// A simple smoke/compile test for new bindings endpoint types. Used to // A simple smoke/compile test for new bindings endpoint types. Used to
// demonstrate look & feel as well as to ensure basic completeness and // demonstrate look & feel as well as to ensure basic completeness and
...@@ -209,6 +262,44 @@ TEST(NewEndpointTypesTest, BasicUsage) { ...@@ -209,6 +262,44 @@ TEST(NewEndpointTypesTest, BasicUsage) {
observer2.WaitForDisconnect(); 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 new_endpoint_types
} // namespace test } // namespace test
} // namespace mojo } // namespace mojo
...@@ -22,3 +22,12 @@ interface WidgetFactory { ...@@ -22,3 +22,12 @@ interface WidgetFactory {
CreateWidget(pending_receiver<Widget> receiver, CreateWidget(pending_receiver<Widget> receiver,
pending_remote<WidgetClient> client); 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}} { ...@@ -48,6 +48,8 @@ namespace {{variant}} {
#include "mojo/public/cpp/bindings/interface_ptr.h" #include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/control_message_handler.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_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h" #include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
......
...@@ -595,6 +595,12 @@ class Generator(generator.Generator): ...@@ -595,6 +595,12 @@ class Generator(generator.Generator):
if mojom.IsPendingReceiverKind(kind): if mojom.IsPendingReceiverKind(kind):
return "mojo::PendingReceiver<%s>" % self._GetNameForKind( return "mojo::PendingReceiver<%s>" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces) 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): if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfo" % self._GetNameForKind( return "%sAssociatedPtrInfo" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces) kind.kind, add_same_module_namespaces=add_same_module_namespaces)
...@@ -685,9 +691,11 @@ class Generator(generator.Generator): ...@@ -685,9 +691,11 @@ class Generator(generator.Generator):
return "mojo::internal::Interface_Data" return "mojo::internal::Interface_Data"
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo::internal::Handle_Data" return "mojo::internal::Handle_Data"
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "mojo::internal::AssociatedInterface_Data" return "mojo::internal::AssociatedInterface_Data"
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo::internal::AssociatedEndpointHandle_Data" return "mojo::internal::AssociatedEndpointHandle_Data"
if mojom.IsEnumKind(kind): if mojom.IsEnumKind(kind):
return "int32_t" return "int32_t"
...@@ -905,9 +913,11 @@ class Generator(generator.Generator): ...@@ -905,9 +913,11 @@ class Generator(generator.Generator):
if mojom.IsPendingReceiverKind(kind): if mojom.IsPendingReceiverKind(kind):
return ("mojo::InterfaceRequestDataView<%sInterfaceBase>" % return ("mojo::InterfaceRequestDataView<%sInterfaceBase>" %
_GetName(kind.kind)) _GetName(kind.kind))
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind) return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "%sAssociatedRequestDataView" % _GetName(kind.kind) return "%sAssociatedRequestDataView" % _GetName(kind.kind)
if mojom.IsGenericHandleKind(kind): if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle" return "mojo::ScopedHandle"
......
...@@ -221,9 +221,11 @@ def DecodeMethod(context, kind, offset, bit): ...@@ -221,9 +221,11 @@ def DecodeMethod(context, kind, offset, bit):
return 'readInterfaceRequest' return 'readInterfaceRequest'
if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind): if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
return 'readServiceInterface' return 'readServiceInterface'
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return 'readAssociatedInterfaceRequestNotSupported' return 'readAssociatedInterfaceRequestNotSupported'
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return 'readAssociatedServiceInterfaceNotSupported' return 'readAssociatedServiceInterfaceNotSupported'
return _spec_to_decode_method[kind.spec] return _spec_to_decode_method[kind.spec]
methodName = _DecodeMethodName(kind) methodName = _DecodeMethodName(kind)
...@@ -282,9 +284,11 @@ def GetJavaType(context, kind, boxed=False, with_generics=True): ...@@ -282,9 +284,11 @@ def GetJavaType(context, kind, boxed=False, with_generics=True):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' % return ('org.chromium.mojo.bindings.InterfaceRequest<%s>' %
GetNameForKind(context, kind.kind)) GetNameForKind(context, kind.kind))
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return 'org.chromium.mojo.bindings.AssociatedInterfaceNotSupported' return 'org.chromium.mojo.bindings.AssociatedInterfaceNotSupported'
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return 'org.chromium.mojo.bindings.AssociatedInterfaceRequestNotSupported' return 'org.chromium.mojo.bindings.AssociatedInterfaceRequestNotSupported'
if mojom.IsMapKind(kind): if mojom.IsMapKind(kind):
if with_generics: if with_generics:
...@@ -425,7 +429,8 @@ def TempDir(): ...@@ -425,7 +429,8 @@ def TempDir():
def EnumCoversContinuousRange(kind): def EnumCoversContinuousRange(kind):
if not kind.fields: if not kind.fields:
return False 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: if kind.max_value - kind.min_value + 1 != number_of_unique_keys:
return False return False
return True return True
......
...@@ -401,10 +401,12 @@ class Generator(generator.Generator): ...@@ -401,10 +401,12 @@ class Generator(generator.Generator):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo.InterfaceRequest" return "mojo.InterfaceRequest"
# TODO(calamity): Support associated interfaces properly. # TODO(calamity): Support associated interfaces properly.
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "mojo.AssociatedInterfacePtrInfo" return "mojo.AssociatedInterfacePtrInfo"
# TODO(calamity): Support associated interface requests properly. # TODO(calamity): Support associated interface requests properly.
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo.AssociatedInterfaceRequest" return "mojo.AssociatedInterfaceRequest"
# TODO(calamity): Support enums properly. # TODO(calamity): Support enums properly.
...@@ -459,10 +461,12 @@ class Generator(generator.Generator): ...@@ -459,10 +461,12 @@ class Generator(generator.Generator):
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return name + "Request" return name + "Request"
# TODO(calamity): Support associated interfaces properly. # TODO(calamity): Support associated interfaces properly.
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "Object" return "Object"
# TODO(calamity): Support associated interface requests properly. # TODO(calamity): Support associated interface requests properly.
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "Object" return "Object"
raise Exception("No valid closure type: %s" % kind) raise Exception("No valid closure type: %s" % kind)
...@@ -553,11 +557,13 @@ class Generator(generator.Generator): ...@@ -553,11 +557,13 @@ class Generator(generator.Generator):
return "mojo.internal.InterfaceProxy(%sProxy)" % name return "mojo.internal.InterfaceProxy(%sProxy)" % name
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
return "mojo.internal.InterfaceRequest(%sRequest)" % name return "mojo.internal.InterfaceRequest(%sRequest)" % name
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
# TODO(rockot): Implement associated interfaces. # TODO(rockot): Implement associated interfaces.
return "mojo.internal.AssociatedInterfaceProxy(%sProxy)" % ( return "mojo.internal.AssociatedInterfaceProxy(%sProxy)" % (
name) name)
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "mojo.internal.AssociatedInterfaceRequest(%s)" % name return "mojo.internal.AssociatedInterfaceRequest(%s)" % name
return name return name
...@@ -594,9 +600,11 @@ class Generator(generator.Generator): ...@@ -594,9 +600,11 @@ class Generator(generator.Generator):
if (mojom.IsInterfaceRequestKind(field.kind) or if (mojom.IsInterfaceRequestKind(field.kind) or
mojom.IsPendingReceiverKind(field.kind)): mojom.IsPendingReceiverKind(field.kind)):
return "new bindings.InterfaceRequest()" return "new bindings.InterfaceRequest()"
if mojom.IsAssociatedInterfaceKind(field.kind): if (mojom.IsAssociatedInterfaceKind(field.kind) or
mojom.IsPendingAssociatedRemoteKind(field.kind)):
return "new associatedBindings.AssociatedInterfacePtrInfo()" return "new associatedBindings.AssociatedInterfacePtrInfo()"
if mojom.IsAssociatedInterfaceRequestKind(field.kind): if (mojom.IsAssociatedInterfaceRequestKind(field.kind) or
mojom.IsPendingAssociatedReceiverKind(field.kind)):
return "new associatedBindings.AssociatedInterfaceRequest()" return "new associatedBindings.AssociatedInterfaceRequest()"
if mojom.IsEnumKind(field.kind): if mojom.IsEnumKind(field.kind):
return "0" return "0"
...@@ -641,10 +649,12 @@ class Generator(generator.Generator): ...@@ -641,10 +649,12 @@ class Generator(generator.Generator):
return "codec.%s" % ( return "codec.%s" % (
"NullableInterfaceRequest" if mojom.IsNullableKind(kind) "NullableInterfaceRequest" if mojom.IsNullableKind(kind)
else "InterfaceRequest") else "InterfaceRequest")
if mojom.IsAssociatedInterfaceKind(kind): if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return "codec.%s" % ("NullableAssociatedInterfacePtrInfo" return "codec.%s" % ("NullableAssociatedInterfacePtrInfo"
if mojom.IsNullableKind(kind) else "AssociatedInterfacePtrInfo") if mojom.IsNullableKind(kind) else "AssociatedInterfacePtrInfo")
if mojom.IsAssociatedInterfaceRequestKind(kind): if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return "codec.%s" % ("NullableAssociatedInterfaceRequest" return "codec.%s" % ("NullableAssociatedInterfaceRequest"
if mojom.IsNullableKind(kind) else "AssociatedInterfaceRequest") if mojom.IsNullableKind(kind) else "AssociatedInterfaceRequest")
if mojom.IsEnumKind(kind): if mojom.IsEnumKind(kind):
...@@ -812,10 +822,12 @@ class Generator(generator.Generator): ...@@ -812,10 +822,12 @@ class Generator(generator.Generator):
elif mojom.IsPendingRemoteKind(kind): elif mojom.IsPendingRemoteKind(kind):
return '{0}.{1}Ptr'.format(kind.kind.module.namespace, return '{0}.{1}Ptr'.format(kind.kind.module.namespace,
kind.kind.name) kind.kind.name)
elif mojom.IsAssociatedInterfaceRequestKind(kind): elif (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace, return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace,
kind.kind.name) kind.kind.name)
elif mojom.IsAssociatedInterfaceKind(kind): elif (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
return '{0}.{1}AssociatedPtr'.format(kind.kind.module.namespace, return '{0}.{1}AssociatedPtr'.format(kind.kind.module.namespace,
kind.kind.name) kind.kind.name)
elif mojom.IsSharedBufferKind(kind): elif mojom.IsSharedBufferKind(kind):
......
...@@ -520,6 +520,36 @@ class PendingReceiver(ReferenceKind): ...@@ -520,6 +520,36 @@ class PendingReceiver(ReferenceKind):
self.kind = kind 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): class InterfaceRequest(ReferenceKind):
ReferenceKind.AddSharedProperty('kind') ReferenceKind.AddSharedProperty('kind')
...@@ -877,6 +907,14 @@ def IsPendingReceiverKind(kind): ...@@ -877,6 +907,14 @@ def IsPendingReceiverKind(kind):
return isinstance(kind, PendingReceiver) return isinstance(kind, PendingReceiver)
def IsPendingAssociatedRemoteKind(kind):
return isinstance(kind, PendingAssociatedRemote)
def IsPendingAssociatedReceiverKind(kind):
return isinstance(kind, PendingAssociatedReceiver)
def IsEnumKind(kind): def IsEnumKind(kind):
return isinstance(kind, Enum) return isinstance(kind, Enum)
...@@ -923,7 +961,9 @@ def IsAnyHandleOrInterfaceKind(kind): ...@@ -923,7 +961,9 @@ def IsAnyHandleOrInterfaceKind(kind):
def IsAssociatedKind(kind): def IsAssociatedKind(kind):
return (IsAssociatedInterfaceKind(kind) or return (IsAssociatedInterfaceKind(kind) or
IsAssociatedInterfaceRequestKind(kind)) IsAssociatedInterfaceRequestKind(kind) or
IsPendingAssociatedRemoteKind(kind) or
IsPendingAssociatedReceiverKind(kind))
def HasCallbacks(interface): def HasCallbacks(interface):
......
...@@ -45,13 +45,14 @@ class PackedField(object): ...@@ -45,13 +45,14 @@ class PackedField(object):
def GetSizeForKind(cls, kind): def GetSizeForKind(cls, kind):
if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct, if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct,
mojom.Interface, mojom.AssociatedInterface, mojom.Interface, mojom.AssociatedInterface,
mojom.PendingRemote)): mojom.PendingRemote, mojom.PendingAssociatedRemote)):
return 8 return 8
if isinstance(kind, mojom.Union): if isinstance(kind, mojom.Union):
return 16 return 16
if isinstance(kind, (mojom.InterfaceRequest, mojom.PendingReceiver)): if isinstance(kind, (mojom.InterfaceRequest, mojom.PendingReceiver)):
kind = mojom.MSGPIPE kind = mojom.MSGPIPE
if isinstance(kind, mojom.AssociatedInterfaceRequest): if isinstance(kind, (mojom.AssociatedInterfaceRequest,
mojom.PendingAssociatedReceiver)):
return 4 return 4
if isinstance(kind, mojom.Enum): if isinstance(kind, mojom.Enum):
# TODO(mpcomplete): what about big enums? # TODO(mpcomplete): what about big enums?
......
...@@ -70,7 +70,8 @@ def _MapKind(kind): ...@@ -70,7 +70,8 @@ def _MapKind(kind):
base_kind = _MapKind(kind[0:-1]) base_kind = _MapKind(kind[0:-1])
# NOTE: This doesn't rule out enum types. Those will be detected later, when # NOTE: This doesn't rule out enum types. Those will be detected later, when
# cross-reference is established. # 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: if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds:
raise Exception( raise Exception(
'A type (spec "%s") cannot be made nullable' % base_kind) 'A type (spec "%s") cannot be made nullable' % base_kind)
...@@ -94,6 +95,12 @@ def _MapKind(kind): ...@@ -94,6 +95,12 @@ def _MapKind(kind):
if kind.startswith('rcv<'): if kind.startswith('rcv<'):
assert kind.endswith('>') assert kind.endswith('>')
return 'rcv:' + _MapKind(kind[4:-1]) 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: if kind in map_to_kind:
return map_to_kind[kind] return map_to_kind[kind]
return 'x:' + kind return 'x:' + kind
...@@ -213,6 +220,10 @@ def _Kind(kinds, spec, scope): ...@@ -213,6 +220,10 @@ def _Kind(kinds, spec, scope):
kind = mojom.PendingRemote(_Kind(kinds, spec[4:], scope)) kind = mojom.PendingRemote(_Kind(kinds, spec[4:], scope))
elif spec.startswith('rcv:'): elif spec.startswith('rcv:'):
kind = mojom.PendingReceiver(_Kind(kinds, spec[4:], scope)) 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['): elif spec.startswith('m['):
# Isolate the two types from their brackets. # Isolate the two types from their brackets.
......
...@@ -67,7 +67,9 @@ class Lexer(object): ...@@ -67,7 +67,9 @@ class Lexer(object):
'MAP', 'MAP',
'ASSOCIATED', 'ASSOCIATED',
'PENDING_REMOTE', 'PENDING_REMOTE',
'PENDING_RECEIVER' 'PENDING_RECEIVER',
'PENDING_ASSOCIATED_REMOTE',
'PENDING_ASSOCIATED_RECEIVER',
) )
keyword_map = {} keyword_map = {}
......
...@@ -273,6 +273,8 @@ class Parser(object): ...@@ -273,6 +273,8 @@ class Parser(object):
def p_basictypename(self, p): def p_basictypename(self, p):
"""basictypename : remotetype """basictypename : remotetype
| receivertype | receivertype
| associatedremotetype
| associatedreceivertype
| identifier | identifier
| ASSOCIATED identifier | ASSOCIATED identifier
| handletype""" | handletype"""
...@@ -289,6 +291,16 @@ class Parser(object): ...@@ -289,6 +291,16 @@ class Parser(object):
"""receivertype : PENDING_RECEIVER LANGLE identifier RANGLE""" """receivertype : PENDING_RECEIVER LANGLE identifier RANGLE"""
p[0] = "rcv<%s>" % p[3] 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): def p_handletype(self, p):
"""handletype : HANDLE """handletype : HANDLE
| HANDLE LANGLE NAME RANGLE""" | 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