//----------------------------------------------------------------------------
// Copyright 2012-2025 Joe Lowe
//
// Permission is granted to any person obtaining a copy of this Software,
// to deal in the Software without restriction, including the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and sell copies of
// the Software.
//
// The above copyright and permission notice must be left intact in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS WITHOUT WARRANTY.
//----------------------------------------------------------------------------
// file name:  ptiobuf.h
// created:    2012.03.30
//
// Buffer abstration for user mode, kernel mode, cross platform.
// Simple void* for user mode. Kernel mode maps to system defined
// memory descriptor.
//----------------------------------------------------------------------------
#ifndef PTIOBUF_H
#define PTIOBUF_H
#include "ptpublic.h"
PT_EXTERNC_START

#ifndef PT_IO_DIRECTION_DEFINED
#define PT_IO_DIRECTION_DEFINED
PT_STATIC_CONST( int, pt_io_direction_none, 0);
PT_STATIC_CONST( int, pt_io_direction_recv, 1);
PT_STATIC_CONST( int, pt_io_direction_send, 2);
PT_STATIC_CONST( int, pt_io_direction_both, 3);
#endif

PT_INLINE2 const char* pt_io_direction_text( int direction)
{
   switch (direction)
   {
   case pt_io_direction_send: return "send";
   case pt_io_direction_recv: return "recv";
   case pt_io_direction_both: return "both";
   }
   return "none";
}

#ifndef KERNEL

PT_TYPE_DEFINE( pt_iobuf_t)
{
   PT_UINT8 data[16];
};
PT_INLINE pt_iobuf_t* pt_iobuf( void* data) { return PT_SCASTP( pt_iobuf_t*, data); }
PT_INLINE const pt_iobuf_t* pt_iobuf_const( const void* data) { return PT_SCASTP( const pt_iobuf_t*, data); }
PT_INLINE void* pt_iobuf_map( pt_iobuf_t* buf, PT_SIZE_T off) { return buf ? buf->data + off : nullptr; }
PT_INLINE const void* pt_iobuf_map_const( const pt_iobuf_t* buf, PT_SIZE_T off) { return buf ? buf->data + off : nullptr; }
PT_INLINE void pt_iobuf_dest_copy( pt_iobuf_t* buf, PT_SIZE_T off, const void* src, PT_SIZE_T size) { if (buf) memcpy( buf->data + off, src, size); }
PT_INLINE void pt_iobuf_src_copy( const pt_iobuf_t* buf, PT_SIZE_T off, void* dest, PT_SIZE_T size) { if (buf) memcpy( dest, buf->data + off, size); }
PT_INLINE void pt_iobuf_set( pt_iobuf_t* buf, PT_SIZE_T off, PT_UINT8 val, PT_SIZE_T size) { if (buf) memset( buf->data + off, val, size); }
PT_INLINE void pt_iobuf_zero( pt_iobuf_t* buf, PT_SIZE_T off, PT_SIZE_T size) { if (buf) memset( buf->data + off, 0, size); }

PT_TYPE_DEFINE( pt_iobuf_handle_t)
{
   union { const pt_iobuf_t* buf_const; pt_iobuf_t* buf; };
   PT_SIZE_T alloc_size;
};
PT_INLINE pt_iobuf_t* pt_iobuf_get( pt_iobuf_handle_t* bh) { return bh->buf; }

#endif
#ifdef KERNEL
#ifdef _WIN32

PT_TYPE_DEFINE( pt_iobuf_t)
{
   PT_UINT8 mdl[16];
};
PT_INLINE pt_iobuf_t* pt_iobuf( struct _MDL* mdl) { return PT_SCASTP( pt_iobuf_t*, mdl); }
PT_INLINE struct _MDL* pt_iobuf_mdl( const pt_iobuf_t* buf) { return PT_RCAST( struct _MDL*, buf); }

PT_TYPE_DEFINE( pt_iobuf_handle_t)
{
   int flags;
   struct _MDL* mdl;
#ifdef DEBUG
   pt_iobuf_handle_t* alias_of;
   int alias_count;
#endif
};
PT_INLINE pt_iobuf_t* pt_iobuf_get( pt_iobuf_handle_t* bh) { return PT_RCAST( pt_iobuf_t*, bh->mdl); }

#endif
#ifdef __APPLE__
#define PTIOBUF_UNMAPPABLE

#if defined __cplusplus
class IOMemoryDescriptor;
class IOMemoryMap;
#else
PT_TYPE_DECLARE( IOMemoryDescriptor);
PT_TYPE_DECLARE( IOMemoryMap);
#endif
struct uio;

PT_TYPE_DEFINE( pt_iobuf_t)
{
   void* zero1;
   struct uio* uio;
   IOMemoryDescriptor* md;
   union { IOMemoryMap* mm; void* thread; };
   union { void* map; const void* map_const; };
   void* reserved1[3];
};
PT_INLINE pt_iobuf_t* pt_iobuf( pt_iobuf_t* buf) { return buf; }
PT_INLINE IOMemoryDescriptor* pt_iobuf_mdl( const pt_iobuf_t* buf) { return buf ? buf->md : nullptr; }

PT_TYPE_DEFINE( pt_iobuf_handle_t)
{
   int flags;
   pt_iobuf_t base;
#ifdef DEBUG
   pt_iobuf_handle_t* alias_of;
   int alias_count;
#endif
};
PT_INLINE pt_iobuf_t* pt_iobuf_get( pt_iobuf_handle_t* bh) { return &bh->base; }

#endif
#ifdef __linux__
#define PTIOBUF_MAP_FRAGMENT
struct page;
#ifndef KPI_FOLIO_T
#define KPI_FOLIO_T void
#endif

struct page;
PT_TYPE_DEFINE( pt_iobuf_t)
{
   void* zero1;
   union { void* map; const void* map_const; };
   PT_SIZE_T off;
   PT_SIZE_T count;
   struct page** page_list;
   KPI_FOLIO_T** folio_list;
   void* reserved1[2];
};
PT_INLINE pt_iobuf_t* pt_iobuf( pt_iobuf_t* buf) { return buf; }
PT_INLINE pt_iobuf_t* pt_iobuf_mdl( const pt_iobuf_t* buf) { return PT_CCAST( pt_iobuf_t*, buf); }

PT_TYPE_DEFINE( pt_iobuf_handle_t)
{
   int flags;
   PT_SIZE_T mem_size;
   pt_iobuf_t base;
#ifdef DEBUG
   pt_iobuf_handle_t* alias_of;
   int alias_count;
#endif
};
PT_INLINE pt_iobuf_t* pt_iobuf_get( pt_iobuf_handle_t* bh) { return &bh->base; }

#endif
#endif

PT_TYPE_DEFINE( pt_iobufv_t)
{
   union { pt_iobuf_t* buf; const pt_iobuf_t* buf_const; };
   PT_SIZE_T buf_off;
   PT_SIZE_T size;
};

int/*err*/ PT_CCALL pt_iobuf_alloc_init( pt_iobuf_handle_t*, int direction, PT_SIZE_T size);
int/*err*/ PT_CCALL pt_iobuf_mem_init( pt_iobuf_handle_t*, int direction, const void*, PT_SIZE_T size);
void PT_CCALL pt_iobuf_term( pt_iobuf_handle_t*);
void PT_CCALL pt_iobuf_copy( pt_iobuf_t* dest, PT_SIZE_T dest_off, pt_iobuf_t* src, PT_SIZE_T src_off, PT_SIZE_T size);

#ifdef KERNEL
int/*err*/ PT_CCALL pt_iobuf_user_init( pt_iobuf_handle_t*, int direction, const void*, PT_SIZE_T size);
int/*err*/ PT_CCALL pt_iobuf_alias_init( pt_iobuf_handle_t*, pt_iobuf_handle_t* src, int direction, PT_SIZE_T size);
#ifdef __APPLE__
void pt_iobuf_uio_thread_init( pt_iobuf_handle_t*, struct uio*);
int/*err*/ PT_CCALL pt_iobuf_uio_md_init( pt_iobuf_handle_t*, struct uio*, PT_SIZE_T off, PT_SIZE_T size);
int/*err*/ PT_CCALL pt_iobuf_upl_init( pt_iobuf_handle_t*, int direction, void* upl, PT_SIZE_T off, PT_SIZE_T size);
#endif
#ifdef __linux__
int/*err*/ PT_CCALL pt_iobuf_page_list_init( pt_iobuf_handle_t*, struct page**, PT_SIZE_T page_count);
int/*err*/ PT_CCALL pt_iobuf_folio_list_init( pt_iobuf_handle_t*, KPI_FOLIO_T**, PT_SIZE_T page_count);
#endif
void* PT_CCALL pt_iobuf_map( pt_iobuf_t*, PT_SIZE_T off);
const void* PT_CCALL pt_iobuf_map_const( const pt_iobuf_t*, PT_SIZE_T off);
void PT_CCALL pt_iobuf_dest_copy( pt_iobuf_t*, PT_SIZE_T off, const void* src, PT_SIZE_T);
void PT_CCALL pt_iobuf_src_copy( const pt_iobuf_t*, PT_SIZE_T off, void* dest, PT_SIZE_T);
void PT_CCALL pt_iobuf_set( pt_iobuf_t* buf, PT_SIZE_T off, PT_UINT8 val, PT_SIZE_T size);
PT_INLINE void pt_iobuf_zero( pt_iobuf_t* buf, PT_SIZE_T off, PT_SIZE_T size) { pt_iobuf_dest_copy( buf, off, nullptr, size); }
#endif

#ifdef PTIOBUF_MAP_FRAGMENT
void* PT_CCALL pt_iobuf_map_fragment( const pt_iobuf_t*, PT_SIZE_T off, PT_SIZE_T* ref_size);
#else
PT_INLINE void* pt_iobuf_map_fragment( const pt_iobuf_t* buf, PT_SIZE_T off, PT_SIZE_T* ref_size) { return pt_iobuf_map( PT_CCAST( pt_iobuf_t*, buf), off); }
#endif
void* PT_CCALL pt_iobufv_map_fragment( const pt_iobufv_t*, PT_SIZE_T off, PT_SIZE_T* ref_size);

PT_INLINE void* pt_iobuf_get_map( pt_iobuf_handle_t* bh, PT_SIZE_T off) { return pt_iobuf_map( pt_iobuf_get( bh), off); }
void PT_CCALL pt_iobufv_dest_copy( pt_iobufv_t* dest, PT_SIZE_T dest_off, const void* src, PT_SIZE_T);
void PT_CCALL pt_iobufv_src_copy( const pt_iobufv_t* src, PT_SIZE_T src_off, void* dest, PT_SIZE_T);
void PT_CCALL pt_iobufv_copy( pt_iobufv_t* dest, PT_SIZE_T dest_off, const pt_iobufv_t* src, PT_SIZE_T src_off, PT_SIZE_T size);
void PT_CCALL pt_iobufv_set( pt_iobufv_t*, PT_SIZE_T off, PT_UINT8 val, PT_SIZE_T size);
void PT_CCALL pt_iobufv_zero( pt_iobufv_t*, PT_SIZE_T off, PT_SIZE_T size);
size_t PT_CCALL pt_iobufv_cmp( pt_iobufv_t* buf1, PT_SIZE_T off1, const pt_iobufv_t* buf2, PT_SIZE_T off2, PT_SIZE_T size);

PT_EXTERNC_END
#endif
