//
//  tb_transport_private.h
//  Tightbeam

#ifndef __TIGHTBEAM_TRANSPORT_PRIVATE_H
#define __TIGHTBEAM_TRANSPORT_PRIVATE_H

#include <sys/cdefs.h>
__ptrcheck_abi_assume_single()

#include <Tightbeam/tb_transport.h>
#include <Tightbeam/tb_transport_external.h>

TB_ASSUME_NONNULL_BEGIN
__TB_BEGIN_DECLS

typedef struct tb_transport_static_context_s {
    _Alignas(8) char _opaque[TB_TRANSPORT_CONTEXT_SIZE];
} tb_transport_static_context_s, *tb_transport_static_context_t;

struct tb_transport_connection_blocks_s {
    tb_transport_message_handler_b __TB_UNSAFE_UNRETAINED _Nullable
            connection_message_handler;

    tb_transport_message_handler_f _Nullable connection_message_handler_f;
    void* _Nullable connection_message_handler_context;
} __TB_WARN_UNUSED_RESULT;

struct tb_transport_vtable_s {
    tb_transport_send_message_f transport_send_message;
    tb_transport_activate_f transport_client_activate;
    tb_transport_activate_f transport_service_activate;
    tb_transport_construct_message_buffer_f transport_construct_message;
    tb_transport_destruct_message_buffer_f transport_destruct_message;
    tb_transport_reset_message_buffer_f transport_reset_message;
    tb_transport_supports_multipart_messages_f transport_supports_multipart_messages;
    tb_transport_get_tx_buffer_size_f transport_get_tx_buffer_size;
    tb_transport_destruct_f transport_destruct;
    tb_transport_construct_message_buffer_2_f transport_construct_message_2;
    tb_transport_destruct_message_buffer_2_f transport_destruct_message_2;
    tb_transport_reset_message_buffer_2_f transport_reset_message_2;
} __TB_WARN_UNUSED_RESULT;

typedef struct _tb_transport_s {
    /// A vtable of methods that the owning connection will call into. This
    /// represents the API surface from the connection to the (->) transport.
    struct tb_transport_vtable_s vtable;

    const struct tb_transport_vtable_s *static_vtable;

    /// A collection of blocks the connection has handed us that represent the
    /// transport (->) to connection API.
    struct tb_transport_connection_blocks_s con_table;

    /// Transport-specific data. Must maintain for out-of-tree transports.
    void *transport_priv;

    /// In-line transport-specific data. Used by in-tree transports to avoid an
    /// additional allocation.
    tb_transport_static_context_s inline_priv;
} _tb_transport_s, *_tb_transport_t __TB_WARN_UNUSED_RESULT;

#ifdef __RTKIT__
// rdar://117555447 Remove this redefintion once RTKit has moved over to using
// accessors instead of direct access to the transport structure (or casting
// the public structure to the private structure)
struct tb_transport_s {
    /// A vtable of methods that the owning connection will call into. This represents the API surface
    /// from the connection to the (->) transport.
    struct tb_transport_vtable_s vtable;

    const struct tb_transport_vtable_s *static_vtable;

    /// A collection of blocks the connection has handed us that represent the transport (->) to connection
    /// API.
    struct tb_transport_connection_blocks_s con_table;

    /// Transport-specific data. Must maintain for out-of-tree transports.
    void *transport_priv;

    /// In-line transport-specific data. Used by in-tree transports to avoid an additional allocation.
    tb_transport_static_context_s inline_priv;
};
#endif

// See comment in cL4_transport_internal.h for why this is a `>=` check.
_Static_assert(sizeof(struct tb_transport_s) >= sizeof(struct _tb_transport_s), "");

typedef uint8_t * __single tb_transport_message_payload_t;
typedef void * __single tb_transport_context_t;

// Make the field of this type usable for data structures
#define TB_TRANSPORT_EXTRA_DATA_SIZE 48
struct tb_transport_message_buffer_opaque_data_s {
    _Alignas(8) uint8_t opaque[TB_TRANSPORT_EXTRA_DATA_SIZE];
};

struct tb_transport_message_buffer_s {
    /// A pointer to the start of the message payload buffer itself.
    tb_transport_message_payload_t __sized_by(size) payload;

    /// Whether the payload buffer is allocated and managed on the outside.
    bool wrapping;

    /// An offset to the position of the next readable/writable byte in the
    /// message payload buffer, including any reserved space.
    size_t position;

    /// The total size of the message buffer, including reserved or unwritten
    /// content.
    size_t size;

    /// The amount of space at the beginning of the buffer reserved for
    /// transport-specific data.
    size_t reserved;

    /// Whether this buffer is owned by the Connection layer or the transport.
    /// There are cases where the Connection layer may need to manually create
    /// a transport buffer, for example when sending a message that's larger
    /// than the transport can send in a single IPC payload. This flag will
    /// only be set by the Connection layer.
    bool connection_owned;

    bool destructed;

    /// Flags associated with the buffer that are to be interpreted by the
    /// transport.
    tb_transport_flags_t flags;

    /// A pointer to a transport-specific context.
    _Nullable tb_transport_context_t context;

    /// A bit of caller-provided memory for transport-specific data
    struct tb_transport_message_buffer_opaque_data_s data;
} __TB_WARN_UNUSED_RESULT;

TB_EXPORT
void
tb_transport_destruct(tb_transport_t transport);

/// Initialize an empty transport message buffer. This will initialize all fields to 0 and pointers to NULL.
///
/// @param buffer
/// The buffer to initialize.
TB_EXPORT
void
tb_transport_initialize_message_buffer(
        struct tb_transport_message_buffer_s *buffer);

/// Reset a transport message buffer. This will initialize all connection-owned fields to 0 and pointers to NULL.
///
/// @param buffer
/// The buffer to initialize.
TB_EXPORT
void
tb_transport_reset_message_buffer(struct tb_transport_message_buffer_s *buffer);

/// Get the private data stored in the provided transport.
///
/// @param tpt
/// The transport to retrieve the private data for.
///
/// @return A pointer to the transport-private data, NULL if not set.
TB_EXPORT
void *
tb_transport_get_transport_private(tb_transport_t tpt);

TB_EXPORT
void *
tb_transport_get_context(tb_transport_t tpt);

/// Perform a deep copy of a transport message buffer. This will NOT copy the
/// context or data pointers. These must be copied over manually as they are
/// transport owned.
///
/// @param dst
/// The message buffer into which to copy the contents from `src`.
///
/// @param src
/// The message buffer from which to copy contents into `dst`.
TB_EXPORT
void
tb_transport_message_buffer_deep_copy(tb_transport_message_buffer_t dst,
        tb_transport_message_buffer_t src);

__TB_END_DECLS
TB_ASSUME_NONNULL_END

#endif // __TIGHTBEAM_TRANSPORT_PRIVATE_H
