blob: e95a9415fbf5f0b7bc843d119ab6a06ab76be173 [file] [log] [blame]
// 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_RECEIVER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
#include <utility>
#include "base/macros.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
// A PendingReceiver receives and accumulates a queue of incoming Interface
// method calls made by a single corresponding Remote. PendingReceiver instances
// may be freely moved to another thread/sequence, or even transferred to
// another process via a Mojo interface call (see pending_receiver<T> syntax in
// mojom IDL).
//
// This object should eventually be consumed to bind a Receiver, which will then
// begin dispatching any queued and future incoming method calls to a local
// implementation of Interface. See Receiver documentation for more details.
//
// NOTE: This object is essentially semantic sugar wrapping a message pipe
// handle that is expected to receive Interface messages from a Remote. As such,
// consumers who know what they're doing (i.e. who are confident about what lies
// on the other end of a pipe) may freely convert between a PendingReceiver and
// a raw message pipe handle.
template <typename Interface>
class PendingReceiver {
public:
// Constructs an invalid PendingReceiver. This object is not entangled with
// any Remote and cannot be used to bind a Receiver.
//
// A valid PendingReceiver is commonly obtained by calling
// |Remote::BindNewPipeAndPassReceiver()| on an existing unbound Remote
// instance or less commonly by calling calling
// |PendingRemote::InitWithNewPipeAndPassReceiver()| on an existing but
// invalid PendingRemote instance.
PendingReceiver() = default;
PendingReceiver(PendingReceiver&&) noexcept = default;
// Temporary implicit move constructor to aid in converting from use of
// InterfaceRequest<Interface> to PendingReceiver.
PendingReceiver(InterfaceRequest<Interface>&& request)
: PendingReceiver(request.PassMessagePipe()) {
set_connection_group(request.PassConnectionGroupRef());
}
// Constructs a valid PendingReceiver from a valid raw message pipe handle.
explicit PendingReceiver(ScopedMessagePipeHandle pipe)
: state_(std::move(pipe)) {}
~PendingReceiver() = default;
PendingReceiver& operator=(PendingReceiver&&) noexcept = default;
// Temporary implicit conversion operator to InterfaceRequest<Interface> to
// aid in converting usage to PendingReceiver.
operator InterfaceRequest<Interface>() && {
InterfaceRequest<Interface> request(PassPipe());
request.set_connection_group(PassConnectionGroupRef());
return request;
}
// Indicates whether the PendingReceiver is valid, meaning it can ne used to
// bind a Receiver that wants to begin dispatching method calls made by the
// entangled Remote.
bool is_valid() const { return state_.pipe.is_valid(); }
explicit operator bool() const { return is_valid(); }
// Resets this PendingReceiver to an invalid state. If it was entangled with a
// Remote or PendingRemote, that object remains in a valid state and will
// eventually detect that its receiver is gone. Any calls it makes will
// effectively be dropped.
void reset() { state_.reset(); }
// Like above but provides a reason for the disconnection.
void ResetWithReason(uint32_t reason, const std::string& description) {
InterfaceRequest<Interface>(PassPipe())
.ResetWithReason(reason, description);
}
// Passes ownership of this PendingReceiver's message pipe handle. After this
// call, the PendingReceiver is no longer in a valid state and can no longer
// be used to bind a Receiver.
ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT {
return std::move(state_.pipe);
}
// Assigns this PendingReceiver to the ConnectionGroup referenced by |ref|.
// Any Receiver which binds this PendingReceiver will inherit the Ref.
void set_connection_group(ConnectionGroup::Ref ref) {
state_.connection_group = std::move(ref);
}
const ConnectionGroup::Ref& connection_group() const {
return state_.connection_group;
}
// Passes ownership of this PendingReceiver's ConnectionGroup Ref, removing it
// from its group.
ConnectionGroup::Ref PassConnectionGroupRef() {
return std::move(state_.connection_group);
}
// For internal Mojo use only.
internal::PendingReceiverState* internal_state() { return &state_; }
private:
internal::PendingReceiverState state_;
DISALLOW_COPY_AND_ASSIGN(PendingReceiver);
};
class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) NullReceiver {
public:
template <typename Interface>
operator PendingReceiver<Interface>() const {
return PendingReceiver<Interface>();
}
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_