// WARNING: This file is machine generated by fidlgen.

#include <fidl/test/foreigntypeinresponseusedthroughcompose/llcpp/fidl.h>

#include <memory>

namespace llcpp {

namespace fidl {
namespace test {
namespace foreigntypeinresponseusedthroughcompose {

namespace {

[[maybe_unused]] constexpr uint64_t kTop_GetFoo_Ordinal = 7703637629648977298lu;
extern "C" const fidl_type_t
    fidl_test_foreigntypeinresponseusedthroughcompose_TopGetFooRequestTable;
extern "C" const fidl_type_t
    fidl_test_foreigntypeinresponseusedthroughcompose_TopGetFooResponseTable;

}  // namespace
Top::ResultOf::GetFoo::GetFoo(zx_handle_t _client) {
  GetFooRequest::OwnedEncodedMessage _request(zx_txid_t(0));
  _request.GetOutgoingMessage().Call<GetFooResponse>(
      _client, bytes_,
      GetFooResponse::PrimarySize + GetFooResponse::MaxOutOfLine);
  status_ = _request.status();
  error_ = _request.error();
}

Top::ResultOf::GetFoo::GetFoo(zx_handle_t _client, zx_time_t _deadline) {
  GetFooRequest::OwnedEncodedMessage _request(zx_txid_t(0));
  _request.GetOutgoingMessage().Call<GetFooResponse>(
      _client, bytes_,
      GetFooResponse::PrimarySize + GetFooResponse::MaxOutOfLine, _deadline);
  status_ = _request.status();
  error_ = _request.error();
}

Top::UnownedResultOf::GetFoo::GetFoo(zx_handle_t _client,
                                     uint8_t* _response_bytes,
                                     uint32_t _response_byte_capacity)
    : bytes_(_response_bytes) {
  GetFooRequest::OwnedEncodedMessage _request(zx_txid_t(0));
  _request.GetOutgoingMessage().Call<GetFooResponse>(_client, _response_bytes,
                                                     _response_byte_capacity);
  status_ = _request.status();
  error_ = _request.error();
}

Top::ResultOf::GetFoo Top::ClientImpl::GetFoo_Sync() {
  if (auto _channel = ::fidl::internal::ClientBase::GetChannel()) {
    return ResultOf::GetFoo(_channel->handle());
  }
  return Top::ResultOf::GetFoo(
      ::fidl::Result(ZX_ERR_CANCELED, ::fidl::kErrorChannelUnbound));
}

Top::UnownedResultOf::GetFoo Top::ClientImpl::GetFoo_Sync(
    ::fidl::BufferSpan _response_buffer) {
  if (auto _channel = ::fidl::internal::ClientBase::GetChannel()) {
    return UnownedResultOf::GetFoo(_channel->handle(), _response_buffer.data,
                                   _response_buffer.capacity);
  }
  return Top::UnownedResultOf::GetFoo(
      ::fidl::Result(ZX_ERR_CANCELED, ::fidl::kErrorChannelUnbound));
}

Top::GetFooResponseContext::GetFooResponseContext()
    : ::fidl::internal::ResponseContext(GetFooResponse::Type,
                                        kTop_GetFoo_Ordinal) {}

void Top::GetFooResponseContext::OnReply(uint8_t* reply) {
  OnReply(reinterpret_cast<GetFooResponse*>(reply));
}

::fidl::Result Top::ClientImpl::GetFoo(
    ::fit::callback<void(GetFooResponse* response)> _cb) {
  class ResponseContext final : public GetFooResponseContext {
   public:
    ResponseContext(::fit::callback<void(GetFooResponse* response)> cb)
        : cb_(std::move(cb)) {}

    void OnReply(GetFooResponse* response) override {
      cb_(response);

      delete this;
    }

    void OnError() override { delete this; }

   private:
    ::fit::callback<void(GetFooResponse* response)> cb_;
  };

  auto* _context = new ResponseContext(std::move(_cb));
  ::fidl::internal::ClientBase::PrepareAsyncTxn(_context);
  GetFooRequest::OwnedEncodedMessage _request(_context->Txid());
  return _request.GetOutgoingMessage().Write(this, _context);
}

::fidl::Result Top::ClientImpl::GetFoo(GetFooResponseContext* _context) {
  ::fidl::internal::ClientBase::PrepareAsyncTxn(_context);

  GetFooRequest::OwnedEncodedMessage _request(_context->Txid());
  return _request.GetOutgoingMessage().Write(this, _context);
}

std::optional<::fidl::UnbindInfo> Top::ClientImpl::DispatchEvent(
    fidl_incoming_msg_t* msg) {
  fidl_message_header_t* hdr =
      reinterpret_cast<fidl_message_header_t*>(msg->bytes);
  switch (hdr->ordinal) {
    default:
      FidlHandleInfoCloseMany(msg->handles, msg->num_handles);
      return ::fidl::UnbindInfo{::fidl::UnbindInfo::kUnexpectedMessage,
                                ZX_ERR_NOT_SUPPORTED};
  }
  return {};
}

namespace methods {

void TopDispatchGetFoo(void* interface, void* bytes, ::fidl::Transaction* txn) {
  Top::Interface::GetFooCompleter::Sync completer(txn);
  reinterpret_cast<Top::Interface*>(interface)->GetFoo(completer);
}

}  // namespace methods

namespace entries {

::fidl::internal::MethodEntry Top[] = {
    {kTop_GetFoo_Ordinal, Top::GetFooRequest::Type, methods::TopDispatchGetFoo},
};

}  // namespace entries

::fidl::DispatchResult Top::TryDispatch(Interface* impl,
                                        fidl_incoming_msg_t* msg,
                                        ::fidl::Transaction* txn) {
  return ::fidl::internal::TryDispatch(
      impl, msg, txn, entries::Top,
      entries::Top +
          sizeof(entries::Top) / sizeof(::fidl::internal::MethodEntry));
}

::fidl::DispatchResult Top::Dispatch(Interface* impl, fidl_incoming_msg_t* msg,
                                     ::fidl::Transaction* txn) {
  ::fidl::DispatchResult dispatch_result = TryDispatch(impl, msg, txn);
  if (dispatch_result == ::fidl::DispatchResult::kNotFound) {
    FidlHandleInfoCloseMany(msg->handles, msg->num_handles);
    txn->InternalError(
        {::fidl::UnbindInfo::kUnexpectedMessage, ZX_ERR_NOT_SUPPORTED});
  }
  return dispatch_result;
}

::fidl::DispatchResult Top::Interface::dispatch_message(
    fidl_incoming_msg_t* msg, ::fidl::Transaction* txn) {
  return Top::Dispatch(this, msg, txn);
}

::fidl::Result Top::Interface::GetFooCompleterBase::Reply(
    ::llcpp::bottom::Foo foo) {
  GetFooResponse::OwnedEncodedMessage _response{foo};
  return CompleterBase::SendReply(&_response.GetOutgoingMessage());
}

::fidl::Result Top::Interface::GetFooCompleterBase::Reply(
    ::fidl::BufferSpan _buffer, ::llcpp::bottom::Foo foo) {
  GetFooResponse::UnownedEncodedMessage _response(_buffer.data,
                                                  _buffer.capacity, foo);
  return CompleterBase::SendReply(&_response.GetOutgoingMessage());
}

void Top::GetFooRequest::_InitHeader(zx_txid_t _txid) {
  fidl_init_txn_header(&_hdr, _txid, kTop_GetFoo_Ordinal);
}

void Top::GetFooResponse::_InitHeader() {
  fidl_init_txn_header(&_hdr, 0, kTop_GetFoo_Ordinal);
}

}  // namespace foreigntypeinresponseusedthroughcompose
}  // namespace test
}  // namespace fidl
}  // namespace llcpp
