#ifndef MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
#include <type_traits>
#include <utility>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "build/build_config.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.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/message.h"
#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
#include "mojo/public/cpp/bindings/runtime_features.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
template <typename T>
class PendingRemote;
template <typename T>
struct PendingReceiverConverter;
template <typename Interface>
class PendingReceiver {
public:
PendingReceiver() = default;
PendingReceiver(PendingReceiver&&) noexcept = default;
explicit PendingReceiver(ScopedMessagePipeHandle pipe)
: state_(std::move(pipe)) {}
template <typename T,
std::enable_if_t<std::is_same<
PendingReceiver<Interface>,
std::invoke_result_t<decltype(&PendingReceiverConverter<
T>::template To<Interface>),
T&&>>::value>* = nullptr>
PendingReceiver(T&& other)
: PendingReceiver(PendingReceiverConverter<T>::template To<Interface>(
std::forward<T>(other))) {}
PendingReceiver(const PendingReceiver&) = delete;
PendingReceiver& operator=(const PendingReceiver&) = delete;
~PendingReceiver() = default;
PendingReceiver& operator=(PendingReceiver&&) noexcept = default;
bool is_valid() const { return state_.pipe.is_valid(); }
explicit operator bool() const { return is_valid(); }
void reset() { state_.reset(); }
void ResetWithReason(uint32_t reason, const std::string& description) {
CHECK(is_valid()) << "Cannot send reset reason to an invalid handle.";
Message message =
PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
kPrimaryInterfaceId, DisconnectReason(reason, description));
MojoResult result =
WriteMessageNew(state_.pipe.get(), message.TakeMojoMessage(),
MOJO_WRITE_MESSAGE_FLAG_NONE);
DCHECK(result == MOJO_RESULT_OK ||
result == MOJO_RESULT_FAILED_PRECONDITION)
<< "result: " << result;
reset();
}
[[nodiscard]] ScopedMessagePipeHandle PassPipe() {
return std::move(state_.pipe);
}
void set_connection_group(ConnectionGroup::Ref ref) {
state_.connection_group = std::move(ref);
}
const ConnectionGroup::Ref& connection_group() const {
return state_.connection_group;
}
ConnectionGroup::Ref PassConnectionGroupRef() {
return std::move(state_.connection_group);
}
[[nodiscard]] REINITIALIZES_AFTER_MOVE PendingRemote<Interface>
InitWithNewPipeAndPassRemote();
internal::PendingReceiverState* internal_state() { return &state_; }
private:
internal::PendingReceiverState state_;
};
class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) NullReceiver {
public:
template <typename Interface>
operator PendingReceiver<Interface>() const {
return PendingReceiver<Interface>();
}
};
}
#include "mojo/public/cpp/bindings/pending_remote.h"
namespace mojo {
template <typename Interface>
PendingRemote<Interface>
PendingReceiver<Interface>::InitWithNewPipeAndPassRemote() {
DCHECK(!is_valid()) << "PendingReceiver already has a remote";
if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
return PendingRemote<Interface>();
}
MessagePipe pipe;
state_.pipe = std::move(pipe.handle0);
return PendingRemote<Interface>(std::move(pipe.handle1), 0u);
}
}
#endif