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

#include <fidl/test.driveroneway/cpp/driver/wire_messaging.h>

#include <memory>

namespace test_driveroneway {
[[maybe_unused]] constexpr uint64_t kOneWay_Send_Ordinal = 7942965975761529343lu;

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

extern "C" const fidl_type_t test_driveroneway_OneWaySendRequestTable;

#ifdef __Fuchsia__
}  // namespace test_driveroneway
::fdf::WireUnownedResult<::test_driveroneway::OneWay::Send>::WireUnownedResult(::fdf::UnownedClientEnd<::test_driveroneway::OneWay> client_end, const ::fdf::Arena& arena, ::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>* request) {
  constexpr uint32_t buffer_size =
      ::fidl::MaxSizeInChannel<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, ::fidl::MessageDirection::kSending>();
  uint8_t* buffer = static_cast<uint8_t*>(arena.Allocate(buffer_size));

  ::fidl::unstable::UnownedEncodedMessage<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, fidl::internal::DriverTransport> request_message(
      buffer, buffer_size, request);
  auto& outgoing = request_message.GetOutgoingMessage();
  ::fidl::WriteOptions write_options = {
      .outgoing_transport_context =
          ::fidl::internal::OutgoingTransportContext::Create<fidl::internal::DriverTransport>(
              arena.get()),
  };
  outgoing.Write(client_end.handle(), std::move(write_options));
  SetStatus(outgoing);
}
namespace test_driveroneway {
#endif  // __Fuchsia__

#ifdef __Fuchsia__
}  // namespace test_driveroneway
::fidl::Status fidl::internal::WireWeakOnewayClientImpl<::test_driveroneway::OneWay>::Send(const ::test_driveroneway::wire::Payload& payload) {
  FIDL_INTERNAL_DISABLE_AUTO_VAR_INIT
  ::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send> _request_object{payload};

  constexpr uint32_t _buffer_size = ::fidl::AsyncClientMethodBufferSizeInChannel<::test_driveroneway::OneWay::Send>();
  uint8_t* _buffer = static_cast<uint8_t*>(arena_.Allocate(_buffer_size));

  ::fidl::unstable::UnownedEncodedMessage<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, ::fidl::internal::DriverTransport> _request_message(
      _buffer, _buffer_size, &_request_object);
  fidl::WriteOptions _options = {};
  _options.outgoing_transport_context =
      ::fidl::internal::OutgoingTransportContext::Create<::fidl::internal::DriverTransport>(
          arena_.get());
  return _client_base()->SendOneWay(_request_message.GetOutgoingMessage(), std::move(_options));
}
::fidl::Status fidl::internal::WireWeakOnewayBufferClientImpl<::test_driveroneway::OneWay>::Send(const ::test_driveroneway::wire::Payload& payload) {
  constexpr uint32_t _buffer_size = ::fidl::AsyncClientMethodBufferSizeInChannel<::test_driveroneway::OneWay::Send>();
  uint8_t* _buffer = static_cast<uint8_t*>(_arena().Allocate(_buffer_size));

  ::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send> _request{payload};
  ::fidl::unstable::UnownedEncodedMessage<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, ::fidl::internal::DriverTransport> _request_message(
      _buffer, _buffer_size, &_request);
  fidl::WriteOptions _options = {};
  _options.outgoing_transport_context =
      ::fidl::internal::OutgoingTransportContext::Create<::fidl::internal::DriverTransport>(
          _arena().get());
  return _client_base()->SendOneWay(_request_message.GetOutgoingMessage(), std::move(_options));
}
namespace test_driveroneway {
#endif  // __Fuchsia__

}  // namespace test_driveroneway
#ifdef __Fuchsia__

#endif  // __Fuchsia__

#ifdef __Fuchsia__

constexpr ::fidl::internal::MethodEntry fidl::internal::WireServerDispatcher<::test_driveroneway::OneWay>::entries_[] = {
    {
        ::test_driveroneway::kOneWay_Send_Ordinal,
        [](void* interface, ::fidl::IncomingMessage&& msg,
           internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn) {
          fdf::Arena arena(::fidl::internal::TakeDriverArenaFromStorage(storage_view));
          ::fidl::unstable::DecodedMessage<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>> decoded{std::move(msg)};
          if (unlikely(!decoded.ok())) {
            return ::fidl::Status{decoded};
          }
          auto* primary = &decoded.PrimaryObject()->body;
          ::fidl::internal::WireCompleter<::test_driveroneway::OneWay::Send>::Sync completer(txn);
          reinterpret_cast<::fdf::WireServer<::test_driveroneway::OneWay>*>(interface)->Send(
              primary, arena, completer);
          return ::fidl::Status::Ok();
        },
    },
};

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

::fidl::DispatchResult fidl::internal::WireServerDispatcher<::test_driveroneway::OneWay>::TryDispatch(
    ::fdf::WireServer<::test_driveroneway::OneWay>* impl, ::fidl::IncomingMessage& 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_driveroneway::OneWay>::Dispatch(::fdf::WireServer<::test_driveroneway::OneWay>* impl, ::fidl::IncomingMessage&& msg,
                                                                                 internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn) {
  ::fidl::internal::Dispatch(impl, msg, storage_view, txn, entries_, entries_end_);
}
void fdf::WireServer<::test_driveroneway::OneWay>::dispatch_message(
    ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
    ::fidl::internal::MessageStorageViewBase* storage_view) {
  ::fidl::internal::WireServerDispatcher<::test_driveroneway::OneWay>::Dispatch(this, std::move(msg), storage_view, txn);
}
#endif  // __Fuchsia__

void ::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>::_InitHeader() {
  ::fidl::InitTxnHeader(&header, 0, ::test_driveroneway::kOneWay_Send_Ordinal, ::test_driveroneway::kOneWay_Send_DynamicFlags);
}
