using System;
using Unity.Baselib;
using Unity.Baselib.LowLevel;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using ErrorState = Unity.Baselib.LowLevel.Binding.Baselib_ErrorState;
using ErrorCode = Unity.Baselib.LowLevel.Binding.Baselib_ErrorCode;
namespace Unity.Networking.Transport
{
using size_t = UIntPtr;
internal unsafe struct UnsafeBaselibNetworkArray : IDisposable
{
[NativeDisableUnsafePtrRestriction] Binding.Baselib_RegisteredNetwork_Buffer* m_Buffer;
///
/// Initializes a new instance of the UnsafeBaselibNetworkArray struct.
///
///
/// Thrown if the capacity is less then 0 or if the value exceeds
public UnsafeBaselibNetworkArray(int capacity)
{
var totalSize = (long)capacity;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be >= 0");
if (totalSize > int.MaxValue)
throw new ArgumentOutOfRangeException(nameof(capacity), $"Capacity * sizeof(T) cannot exceed {int.MaxValue} bytes");
#endif
var pageInfo = stackalloc Binding.Baselib_Memory_PageSizeInfo[1];
Binding.Baselib_Memory_GetPageSizeInfo(pageInfo);
var defaultPageSize = (ulong)pageInfo->defaultPageSize;
var pageCount = (ulong)1;
if ((ulong) totalSize > defaultPageSize)
{
pageCount = (ulong)math.ceil(totalSize / (double) defaultPageSize);
}
var error = default(ErrorState);
var pageAllocation = Binding.Baselib_Memory_AllocatePages(
pageInfo->defaultPageSize,
pageCount,
1,
Binding.Baselib_Memory_PageState.ReadWrite,
&error);
if (error.code != ErrorCode.Success)
throw new Exception();
UnsafeUtility.MemSet((void*)pageAllocation.ptr, 0, (long)(pageAllocation.pageCount * pageAllocation.pageSize));
m_Buffer = (Binding.Baselib_RegisteredNetwork_Buffer*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf(), UnsafeUtility.AlignOf(), Allocator.Persistent);
*m_Buffer = Binding.Baselib_RegisteredNetwork_Buffer_Register(pageAllocation, &error);
if (error.code != (int)ErrorCode.Success)
{
Binding.Baselib_Memory_ReleasePages(pageAllocation, &error);
*m_Buffer = default;
throw new Exception();
}
}
public void Dispose()
{
var error = default(ErrorState);
var pageAllocation = m_Buffer->allocation;
Binding.Baselib_RegisteredNetwork_Buffer_Deregister(*m_Buffer);
Binding.Baselib_Memory_ReleasePages(pageAllocation, &error);
UnsafeUtility.Free(m_Buffer, Allocator.Persistent);
}
///
/// Gets a element at the specified index, with the size of .
///
/// A pointing to the index supplied.
public Binding.Baselib_RegisteredNetwork_BufferSlice AtIndexAsSlice(int index, uint elementSize)
{
var offset = elementSize * (uint)index;
Binding.Baselib_RegisteredNetwork_BufferSlice slice;
slice.id = m_Buffer->id;
slice.data = (IntPtr)((byte*) m_Buffer->allocation.ptr + offset);
slice.offset = offset;
slice.size = elementSize;
return slice;
}
}
}