namespace AcDream.Core.Net.Packets; /// /// Allocation-free decoded packet view. Every memory member borrows the /// caller's datagram and is valid only while that owner retains the buffer. /// internal readonly record struct BorrowedPacket( PacketHeader Header, BorrowedOptionalHeader Optional, ReadOnlyMemory Body, ReadOnlyMemory FragmentBytes, int FragmentCount) { public BorrowedFragmentEnumerable Fragments => new(FragmentBytes); } internal readonly record struct BorrowedOptionalHeader( uint AckSequence, double TimeSync, float EchoRequestClientTime, uint FlowBytes, ushort FlowInterval, double ConnectRequestServerTime, ulong ConnectRequestCookie, uint ConnectRequestClientId, uint ConnectRequestServerSeed, uint ConnectRequestClientSeed, ReadOnlyMemory RawBytes, ReadOnlyMemory RetransmitRequestBytes, int RetransmitRequestCount, ReadOnlyMemory RejectRetransmitBytes, int RejectRetransmitCount); internal readonly record struct BorrowedMessageFragment( MessageFragmentHeader Header, ReadOnlyMemory Payload); internal readonly struct BorrowedFragmentEnumerable( ReadOnlyMemory encoded) { public Enumerator GetEnumerator() => new(encoded); internal struct Enumerator(ReadOnlyMemory remaining) { private ReadOnlyMemory _remaining = remaining; public BorrowedMessageFragment Current { get; private set; } public bool MoveNext() { if (_remaining.IsEmpty) return false; if (!MessageFragment.TryParseBorrowed( _remaining, out BorrowedMessageFragment fragment, out int consumed)) { throw new InvalidOperationException( "validated packet contained an invalid fragment"); } Current = fragment; _remaining = _remaining.Slice(consumed); return true; } } }