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

// fidl_experiment = output_index_json

#include <fidl/test.drivertwoway/cpp/driver/wire_messaging.h>
#include <lib/fidl_driver/cpp/unknown_interactions.h>

#include <memory>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"

namespace test_drivertwoway {

[[maybe_unused]]
constexpr uint64_t kTwoWay_Add_Ordinal = 989730524426044687lu;

[[maybe_unused]]
constexpr ::fidl::MessageDynamicFlags kTwoWay_Add_DynamicFlags = ::fidl::MessageDynamicFlags::kStrictMethod;

#ifdef __Fuchsia__
}  // namespace test_drivertwoway

::fdf::WireUnownedResult<::test_drivertwoway::TwoWay::Add>::WireUnownedResult(::fdf::UnownedClientEnd<::test_drivertwoway::TwoWay> client_end, const ::fdf::Arena& arena, ::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>* request) {
  constexpr uint32_t buffer_size =
      ::fidl::MaxSizeInChannel<::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>, ::fidl::MessageDirection::kSending>();
  uint8_t* buffer = static_cast<uint8_t*>(arena.Allocate(buffer_size));

  ::fidl::internal::UnownedEncodedMessage<::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>, fidl::internal::DriverTransport> request_message(
      buffer, buffer_size, request);
  auto& outgoing = request_message.GetOutgoingMessage();
  ::fidl::internal::IncomingMessageStorage<::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>> response_storage;
  ::fidl::CallOptions call_options = {
      .outgoing_transport_context =
          ::fidl::internal::OutgoingTransportContext::Create<fidl::internal::DriverTransport>(
              arena.get()),
  };
  ::fit::result decoded = ::fidl::internal::InplaceDecodeTransactionalResponse<::test_drivertwoway::TwoWay::Add>(
      outgoing.Call(client_end.handle(), response_storage.view(), std::move(call_options)));
  SetStatus(::fidl::internal::StatusFromResult(decoded));
  if (ok()) {
    decoded_ = std::move(decoded.value());
    ExtractValueFromDecoded(decoded_.pointer());
  }
  arena_ = std::move(response_storage.arena);
}
namespace test_drivertwoway {

#endif  // __Fuchsia__

#ifdef __Fuchsia__
}  // namespace test_drivertwoway

::fidl::internal::WireBufferThenable<::test_drivertwoway::TwoWay::Add> fidl::internal::WireWeakAsyncBufferClientImpl<::test_drivertwoway::TwoWay>::Add(uint16_t addend1, uint16_t addend2) {
  constexpr uint32_t _buffer_size = ::fidl::AsyncClientMethodBufferSizeInChannel<::test_drivertwoway::TwoWay::Add>();
  uint8_t* _buffer = static_cast<uint8_t*>(_arena().Allocate(_buffer_size));

  ::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add> _request{addend1, addend2};
  fidl::WriteOptions _options = {};
  _options.outgoing_transport_context =
      ::fidl::internal::OutgoingTransportContext::Create<::fidl::internal::DriverTransport>(
          _arena().get());
  return ::fidl::internal::WireBufferThenable<::test_drivertwoway::TwoWay::Add>{
      _client_base(), std::move(_options), _buffer, _buffer_size, &_request};
}

::fdf::WireUnownedResult<::test_drivertwoway::TwoWay::Add>
fidl::internal::WireWeakSyncClientImpl<::test_drivertwoway::TwoWay>::Add(uint16_t addend1, uint16_t addend2) {
  return _client_base()->MakeSyncCallWith(
      [&](std::shared_ptr<::fidl::internal::AnyTransport> _transport) {
        ::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add> _request{addend1, addend2};
        return ::fdf::WireUnownedResult<::test_drivertwoway::TwoWay::Add>(::fdf::UnownedClientEnd<::test_drivertwoway::TwoWay>(_transport->get<::fidl::internal::DriverTransport>()), arena_, &_request);
      });
}
namespace test_drivertwoway {

#endif  // __Fuchsia__

}  // namespace test_drivertwoway

#ifdef __Fuchsia__

#endif  // __Fuchsia__

#ifdef __Fuchsia__

constexpr ::fidl::internal::MethodEntry fidl::internal::WireServerDispatcher<::test_drivertwoway::TwoWay>::entries_[] = {
    {
        ::test_drivertwoway::kTwoWay_Add_Ordinal,
        [](void* interface, ::fidl::EncodedMessage& msg, ::fidl::WireFormatMetadata metadata,
           internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn) {
          fdf::Arena arena(::fidl::internal::TakeDriverArenaFromStorage(storage_view));
          ::fit::result decoded = ::fidl::StandaloneInplaceDecode<::test_drivertwoway::wire::TwoWayAddRequest>(
              std::move(msg), metadata);
          if (unlikely(!decoded.is_ok())) {
            return decoded.error_value();
          }
          ::fidl::internal::WireCompleter<::test_drivertwoway::TwoWay::Add>::Sync completer(txn);
          reinterpret_cast<::fdf::WireServer<::test_drivertwoway::TwoWay>*>(interface)->Add(
              decoded.value().pointer(),
              arena,
              completer);
          return ::fidl::Status::Ok();
        },
    },
};

const ::fidl::internal::MethodEntry* fidl::internal::WireServerDispatcher<::test_drivertwoway::TwoWay>::entries_end_ =
    &entries_[1];

::fidl::DispatchResult fidl::internal::WireServerDispatcher<::test_drivertwoway::TwoWay>::TryDispatch(
    ::fdf::WireServer<::test_drivertwoway::TwoWay>* impl, ::fidl::IncomingHeaderAndMessage& msg,
    internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn) {
  return ::fidl::internal::TryDispatch(
      impl, msg, storage_view, txn, entries_, entries_end_);
}

void fidl::internal::WireServerDispatcher<::test_drivertwoway::TwoWay>::Dispatch(::fdf::WireServer<::test_drivertwoway::TwoWay>* impl, ::fidl::IncomingHeaderAndMessage&& msg,
                                                                                 internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn) {
  ::fidl::internal::Dispatch(impl, msg, storage_view, txn, entries_, entries_end_,
                             &unknown_method_handler_entry_);
}

void fdf::WireServer<::test_drivertwoway::TwoWay>::dispatch_message(
    ::fidl::IncomingHeaderAndMessage&& msg, ::fidl::Transaction* txn,
    ::fidl::internal::MessageStorageViewBase* storage_view) {
  ::fidl::internal::WireServerDispatcher<::test_drivertwoway::TwoWay>::Dispatch(this, std::move(msg), storage_view, txn);
}

#endif  // __Fuchsia__

#ifdef __Fuchsia__
void fidl::internal::WireBufferCompleterImpl<::test_drivertwoway::TwoWay::Add>::Reply(uint16_t sum) {
  return MakeReply(sum);
}

void fidl::internal::WireBufferCompleterImpl<::test_drivertwoway::TwoWay::Add>::MakeReply(uint16_t sum) {
  ::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add> _response{sum};
  constexpr uint32_t _buffer_size = ::fidl::ServerReplyBufferSizeInChannel<::test_drivertwoway::TwoWay::Add>();
  uint8_t* _buffer = static_cast<uint8_t*>(_arena().Allocate(_buffer_size));
  ::fidl::internal::UnownedEncodedMessage<
      ::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::DriverTransport>
      _response_message(
          _buffer, _buffer_size, &_response);
  return _core()->SendReply(
      &_response_message.GetOutgoingMessage(),
      ::fidl::internal::OutgoingTransportContext::Create<::fidl::internal::DriverTransport>(
          _arena().get()));
}

#endif  // __Fuchsia__

#ifdef __Fuchsia__
void ::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>::_InitHeader() {
  ::fidl::InitTxnHeader(&header, 0, ::test_drivertwoway::kTwoWay_Add_Ordinal, ::test_drivertwoway::kTwoWay_Add_DynamicFlags);
}

#endif  // __Fuchsia__

void ::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>::_InitHeader() {
  ::fidl::InitTxnHeader(&header, 0, ::test_drivertwoway::kTwoWay_Add_Ordinal, ::test_drivertwoway::kTwoWay_Add_DynamicFlags);
}

#ifdef __Fuchsia__

#endif  // __Fuchsia__

#pragma clang diagnostic pop
