using System;
using Unity.Networking.Transport;
#if UTP_TRANSPORT_2_0_ABOVE
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
#endif
namespace Unity.Netcode.Transports.UTP
{
/// Queue for batched messages received through UTP.
/// This is meant as a companion to .
internal class BatchedReceiveQueue
{
private byte[] m_Data;
private int m_Offset;
private int m_Length;
public bool IsEmpty => m_Length <= 0;
///
/// Construct a new receive queue from a returned by
/// when popping a data event.
///
/// The to construct from.
public BatchedReceiveQueue(DataStreamReader reader)
{
m_Data = new byte[reader.Length];
unsafe
{
fixed (byte* dataPtr = m_Data)
{
#if UTP_TRANSPORT_2_0_ABOVE
reader.ReadBytesUnsafe(dataPtr, reader.Length);
#else
reader.ReadBytes(dataPtr, reader.Length);
#endif
}
}
m_Offset = 0;
m_Length = reader.Length;
}
///
/// Push the entire data from a (as returned by popping an
/// event from a ) to the queue.
///
/// The to push the data of.
public void PushReader(DataStreamReader reader)
{
// Resize the array and copy the existing data to the beginning if there's not enough
// room to copy the reader's data at the end of the existing data.
var available = m_Data.Length - (m_Offset + m_Length);
if (available < reader.Length)
{
if (m_Length > 0)
{
Array.Copy(m_Data, m_Offset, m_Data, 0, m_Length);
}
m_Offset = 0;
while (m_Data.Length - m_Length < reader.Length)
{
Array.Resize(ref m_Data, m_Data.Length * 2);
}
}
unsafe
{
fixed (byte* dataPtr = m_Data)
{
#if UTP_TRANSPORT_2_0_ABOVE
reader.ReadBytesUnsafe(dataPtr + m_Offset + m_Length, reader.Length);
#else
reader.ReadBytes(dataPtr + m_Offset + m_Length, reader.Length);
#endif
}
}
m_Length += reader.Length;
}
/// Pop the next full message in the queue.
/// The message, or the default value if no more full messages.
public ArraySegment PopMessage()
{
if (m_Length < sizeof(int))
{
return default;
}
var messageLength = BitConverter.ToInt32(m_Data, m_Offset);
if (m_Length - sizeof(int) < messageLength)
{
return default;
}
var data = new ArraySegment(m_Data, m_Offset + sizeof(int), messageLength);
m_Offset += sizeof(int) + messageLength;
m_Length -= sizeof(int) + messageLength;
return data;
}
}
}