using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using ZeroLevel.Services.Extensions;
using ZeroLevel.Services.Memory;
namespace ZeroLevel.Services.Serialization
{
    /// 
    /// A wrapper over a MemoryStream for reading, with a check for overflow
    /// 
    public partial class MemoryStreamReader
        : IBinaryReader
    {
        private readonly IViewAccessor _accessor;
        private bool _reverseByteOrder = false;
        public void ReverseByteOrder(bool use_reverse_byte_order)
        {
            _reverseByteOrder = use_reverse_byte_order;
        }
        /// 
        /// End of stream
        /// 
        public bool EOS => _accessor.EOV;
        public MemoryStreamReader(byte[] data)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            _accessor = new StreamVewAccessor(new MemoryStream(data));
        }
        public MemoryStreamReader(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));
            _accessor = new StreamVewAccessor(stream);
        }
        public MemoryStreamReader(MemoryStreamReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException(nameof(reader));
            _accessor = reader._accessor;
        }
        public MemoryStreamReader(IViewAccessor accessor)
        {
            if (accessor == null)
                throw new ArgumentNullException(nameof(accessor));
            _accessor = accessor;
        }
        public long Position => _accessor.Position;
        public void SetPosition(long position) => _accessor.Seek(position);
        /// 
        /// Flag reading
        /// 
        public bool ReadBoolean()
        {
            return BitConverter.ToBoolean(new byte[1] { ReadByte() }, 0);
        }
        /// 
        /// Reading byte
        /// 
        public byte ReadByte()
        {
            var buffer = ReadBuffer(1);
            return buffer[0];
        }
        public char ReadChar()
        {
            var buffer = ReadBuffer(2);
            return BitConverter.ToChar(buffer, 0);
        }
        /// 
        /// Reading bytes
        /// 
        /// 
        public byte[] ReadBytes()
        {
            var length = BitConverter.ToInt32(ReadBuffer(4), 0);
            if (length == 0) return new byte[0];
            return ReadBuffer(length);
        }
        public short ReadShort()
        {
            var buffer = ReadBuffer(2);
            return BitConverter.ToInt16(buffer, 0);
        }
        public ushort ReadUShort()
        {
            var buffer = ReadBuffer(2);
            return BitConverter.ToUInt16(buffer, 0);
        }
        /// 
        /// Read 32-bit integer (4 bytes)
        /// 
        public Int32 ReadInt32()
        {
            var buffer = ReadBuffer(4);
            return BitConverter.ToInt32(buffer, 0);
        }
        public UInt32 ReadUInt32()
        {
            var buffer = ReadBuffer(4);
            return BitConverter.ToUInt32(buffer, 0);
        }
        public decimal ReadDecimal()
        {
            var arr = ReadBuffer(16);
            var p1 = BitConverter.ToInt32(arr, 0);
            var p2 = BitConverter.ToInt32(arr, 4);
            var p3 = BitConverter.ToInt32(arr, 8);
            var p4 = BitConverter.ToInt32(arr, 12);
            return BitConverterExt.ToDecimal(new int[] { p1, p2, p3, p4 });
        }
        /// 
        /// Read integer 64-bit number (8 bytes)
        /// 
        public Int64 ReadLong()
        {
            var buffer = ReadBuffer(8);
            return BitConverter.ToInt64(buffer, 0);
        }
        public UInt64 ReadULong()
        {
            var buffer = ReadBuffer(8);
            return BitConverter.ToUInt64(buffer, 0);
        }
        public TimeSpan ReadTimeSpan()
        {
            return new TimeSpan(ReadLong());
        }
        public float ReadFloat()
        {
            var buffer = ReadBuffer(4);
            return BitConverter.ToSingle(buffer, 0);
        }
        public double ReadDouble()
        {
            var buffer = ReadBuffer(8);
            return BitConverter.ToDouble(buffer, 0);
        }
        /// 
        /// Read string (4 bytes per length + Length bytes)
        /// 
        public string ReadString()
        {
            var length = BitConverter.ToInt32(ReadBuffer(4), 0);
            if (length == 0) return null;
            var buffer = ReadBuffer(length);
            return Encoding.UTF8.GetString(buffer);
        }
        /// 
        /// Read GUID (16 bytes)
        /// 
        public Guid ReadGuid()
        {
            var buffer = ReadBuffer(16);
            return new Guid(buffer);
        }
        /// 
        ///  Reading byte-package (read the size of the specified number of bytes, and then the packet itself read size)
        /// 
        public byte[] ReadBuffer(int count)
        {
            if (CheckOutOfRange(count))
                throw new OutOfMemoryException("Array index out of bounds");
            var buffer = _accessor.ReadBuffer(count).Result;
            if (_reverseByteOrder && count > 1)
            {
                byte b;
                for (int i = 0; i < (count >> 1); i++)
                {
                    b = buffer[i];
                    buffer[i] = buffer[count - i - 1];
                    buffer[count - i - 1] = b;
                }
            }
            return buffer;
        }
        public bool TryReadBuffer(int count, out byte[] buffer)
        {
            if (CheckOutOfRange(count))
            {
                buffer = null;
                return false;
            }
            try
            {
                buffer = _accessor.ReadBuffer(count).Result;
                if (_reverseByteOrder && count > 1)
                {
                    byte b;
                    for (int i = 0; i < (count >> 1); i++)
                    {
                        b = buffer[i];
                        buffer[i] = buffer[count - i - 1];
                        buffer[count - i - 1] = b;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.SystemError(ex, $"[MemoryStreamReader.TryReadBuffer] Fault read {count} bytes");
                buffer = null;
                return false;
            }
            return true;
        }
        /// 
        /// Reading the datetime
        /// 
        /// 
        public DateTime? ReadDateTime()
        {
            var is_null = ReadByte();
            if (is_null == 0) return null;
            var buffer = ReadBuffer(8);
            long deserialized = BitConverter.ToInt64(buffer, 0);
            return DateTime.FromBinary(deserialized);
        }
        
        public IPAddress ReadIP()
        {
            var exists = ReadByte();
            if (exists == 1)
            {
                var addr = ReadBytes();
                return new IPAddress(addr);
            }
            return null;
        }
        public IPEndPoint ReadIPEndpoint()
        {
            var exists = ReadByte();
            if (exists == 1)
            {
                var addr = ReadIP();
                var port = ReadInt32();
                return new IPEndPoint(addr, port);
            }
            return null;
        }
        /// 
        /// Check if data reading is outside the stream
        /// 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool CheckOutOfRange(int offset) => _accessor.CheckOutOfRange(offset);
        #region Extensions
        #region Collections
        private List ReadList(Func read)
        {
            int count = ReadInt32();
            var collection = new List(count);
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    collection.Add(read.Invoke());
                }
            }
            return collection;
        }
        public List ReadCollection()
            where T : IBinarySerializable, new()
        =>
            ReadList(() =>
            {
                var item = new T();
                item.Deserialize(this);
                return item;
            });
        public List ReadStringCollection() => ReadList(ReadString);
        public List ReadIPCollection() => ReadList(ReadIP);
        public List ReadIPEndPointCollection() => ReadList(ReadIPEndpoint);
        public List ReadGuidCollection() => ReadList(ReadGuid);
        public List ReadDateTimeCollection() => ReadList(ReadDateTime);
        public List ReadInt64Collection() => ReadList(ReadLong);
        public List ReadInt32Collection() => ReadList(ReadInt32);
        public List ReadUInt64Collection() => ReadList(ReadULong);
        public List ReadUInt32Collection() => ReadList(ReadUInt32);
        public List ReadCharCollection() => ReadList(ReadChar);
        public List ReadShortCollection() => ReadList(ReadShort);
        public List ReadUShortCollection() => ReadList(ReadUShort);
        public List ReadFloatCollection() => ReadList(ReadFloat);
        public List ReadDoubleCollection() => ReadList(ReadDouble);
        public List ReadBooleanCollection() => ReadList(ReadBoolean);
        public List ReadByteCollection() => ReadList(ReadByte);
        public List ReadByteArrayCollection() => ReadList(ReadBytes);
        public List ReadDecimalCollection() => ReadList(ReadDecimal);
        public List ReadTimeSpanCollection() => ReadList(ReadTimeSpan);
        #endregion
        #region Collections lazy
        private IEnumerable ReadEnumerable(Func read)
        {
            int count = ReadInt32();
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    yield return read.Invoke();
                }
            }
        }
        public IEnumerable ReadCollectionLazy()
            where T : IBinarySerializable, new()
            =>
            ReadEnumerable(() =>
            {
                var item = new T();
                item.Deserialize(this);
                return item;
            });
        public IEnumerable ReadStringCollectionLazy() => ReadEnumerable(ReadString);
        public IEnumerable ReadIPCollectionLazy() => ReadEnumerable(ReadIP);
        public IEnumerable ReadIPEndPointCollectionLazy() => ReadEnumerable(ReadIPEndpoint);
        public IEnumerable ReadGuidCollectionLazy() => ReadEnumerable(ReadGuid);
        public IEnumerable ReadDateTimeCollectionLazy() => ReadEnumerable(ReadDateTime);
        public IEnumerable ReadInt64CollectionLazy() => ReadEnumerable(ReadLong);
        public IEnumerable ReadInt32CollectionLazy() => ReadEnumerable(ReadInt32);
        public IEnumerable ReadUInt64CollectionLazy() => ReadEnumerable(ReadULong);
        public IEnumerable ReadUInt32CollectionLazy() => ReadEnumerable(ReadUInt32);
        public IEnumerable ReadCharCollectionLazy() => ReadEnumerable(ReadChar);
        public IEnumerable ReadShortCollectionLazy() => ReadEnumerable(ReadShort);
        public IEnumerable ReadUShortCollectionLazy() => ReadEnumerable(ReadUShort);
        public IEnumerable ReadFloatCollectionLazy() => ReadEnumerable(ReadFloat);
        public IEnumerable ReadDoubleCollectionLazy() => ReadEnumerable(ReadDouble);
        public IEnumerable ReadBooleanCollectionLazy() => ReadEnumerable(ReadBoolean);
        public IEnumerable ReadByteCollectionLazy() => ReadEnumerable(ReadByte);
        public IEnumerable ReadByteArrayCollectionLazy() => ReadEnumerable(ReadBytes);
        public IEnumerable ReadDecimalCollectionLazy() => ReadEnumerable(ReadDecimal);
        public IEnumerable ReadTimeSpanCollectionLazy() => ReadEnumerable(ReadTimeSpan);
        #endregion
        #region Arrays
        private T[] ReadArray(Func read)
        {
            int count = ReadInt32();
            var array = new T[count];
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    array[i] = read.Invoke();
                }
            }
            return array;
        }
        public T[] ReadArray()
            where T : IBinarySerializable, new()
            =>
            ReadArray(() =>
            {
                var item = new T();
                item.Deserialize(this);
                return item;
            });
        public string[] ReadStringArray() => ReadArray(ReadString);
        public IPAddress[] ReadIPArray() => ReadArray(ReadIP);
        public IPEndPoint[] ReadIPEndPointArray() => ReadArray(ReadIPEndpoint);
        public Guid[] ReadGuidArray() => ReadArray(ReadGuid);
        public DateTime?[] ReadDateTimeArray() => ReadArray(ReadDateTime);
        public Int64[] ReadInt64Array() => ReadArray(ReadLong);
        public Int32[] ReadInt32Array() => ReadArray(ReadInt32);
        public UInt64[] ReadUInt64Array() => ReadArray(ReadULong);
        public UInt32[] ReadUInt32Array() => ReadArray(ReadUInt32);
        public char[] ReadCharArray() => ReadArray(ReadChar);
        public short[] ReadShortArray() => ReadArray(ReadShort);
        public ushort[] ReadUShortArray() => ReadArray(ReadUShort);
        public float[] ReadFloatArray() => ReadArray(ReadFloat);
        public Double[] ReadDoubleArray() => ReadArray(ReadDouble);
        public bool[] ReadBooleanArray() => ReadArray(ReadBoolean);
        public byte[] ReadByteArray() => ReadBytes();
        public byte[][] ReadByteArrayArray() => ReadArray(ReadBytes);
        public decimal[] ReadDecimalArray() => ReadArray(ReadDecimal);
        public TimeSpan[] ReadTimeSpanArray() => ReadArray(ReadTimeSpan);
        #endregion
        public Dictionary ReadDictionary()
        {
            int count = ReadInt32();
            var collection = new Dictionary(count);
            if (count > 0)
            {
                TKey key;
                TValue value;
                for (int i = 0; i < count; i++)
                {
                    key = ReadCompatible();
                    value = ReadCompatible();
                    collection.Add(key, value);
                }
            }
            return collection;
        }
        public ConcurrentDictionary ReadDictionaryAsConcurrent()
        {
            int count = ReadInt32();
            var collection = new ConcurrentDictionary();
            if (count > 0)
            {
                TKey key;
                TValue value;
                for (int i = 0; i < count; i++)
                {
                    key = ReadCompatible();
                    value = ReadCompatible();
                    collection.TryAdd(key, value);
                }
            }
            return collection;
        }
        public T ReadCompatible()
        {
            return MessageSerializer.DeserializeCompatible(this);
        }
        public T Read() where T : IBinarySerializable
        {
            byte type = ReadByte();
            if (type == 0) return default(T);
            var item = (T)Activator.CreateInstance();
            item.Deserialize(this);
            return item;
        }
        public bool TryReadByte(out byte b)
        {
            if (TryReadBuffer(1, out var buffer))
            {
                b = buffer[0];
                return true;
            }
            b = default;
            return false;
        }
        public bool TryRead(out T item) where T : IBinarySerializable
        {
            if (TryReadByte(out var type))
            {
                if (type == 0)
                {
                    item = default(T);
                    return true;
                }
                try
                {
                    var o = (IBinarySerializable)FormatterServices.GetUninitializedObject(typeof(T));
                    o.Deserialize(this);
                    item = (T)o;
                    return true;
                }
                catch (Exception ex)
                {
                    Log.SystemError(ex, "[MemoryStreamReader.TryRead]");
                }
            }
            item = default;
            return false;
        }
        public T Read(object arg) where T : IBinarySerializable
        {
            byte type = ReadByte();
            if (type == 0) return default(T);
            var item = (T)Activator.CreateInstance(typeof(T), arg);
            item.Deserialize(this);
            return item;
        }
        #endregion Extensions
        public void Dispose()
        {
            _accessor.Dispose();
        }
    }
    public partial class MemoryStreamReader
        : IAsyncBinaryReader
    {
        /// 
        ///  Reading byte-package (read the size of the specified number of bytes, and then the packet itself read size)
        /// 
        public async Task ReadBufferAsync(int count)
        {
            if (CheckOutOfRange(count))
                throw new OutOfMemoryException("Array index out of bounds");
            var buffer = await _accessor.ReadBuffer(count);
            if (_reverseByteOrder && count > 1)
            {
                byte b;
                for (int i = 0; i < (count >> 1); i++)
                {
                    b = buffer[i];
                    buffer[i] = buffer[count - i - 1];
                    buffer[count - i - 1] = b;
                }
            }
            return buffer;
        }
        public async Task TryReadBufferAsync(int count, byte[] buffer)
        {
            if (CheckOutOfRange(count))
            {
                buffer = null;
                return false;
            }
            try
            {
                buffer = await _accessor.ReadBuffer(count);
                if (_reverseByteOrder && count > 1)
                {
                    byte b;
                    for (int i = 0; i < (count >> 1); i++)
                    {
                        b = buffer[i];
                        buffer[i] = buffer[count - i - 1];
                        buffer[count - i - 1] = b;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.SystemError(ex, $"[MemoryStreamReader.TryReadBufferAsync] Fault read {count} bytes");
                buffer = null;
                return false;
            }
            return true;
        }
        /// 
        /// Flag reading
        /// 
        public async Task ReadBooleanAsync()
        {
            return BitConverter.ToBoolean(new byte[1] { await ReadByteAsync() }, 0);
        }
        /// 
        /// Reading byte
        /// 
        public async Task ReadByteAsync()
        {
            var buffer = await ReadBufferAsync(1);
            return buffer[0];
        }
        public async Task ReadCharAsync()
        {
            var buffer = await ReadBufferAsync(2);
            return BitConverter.ToChar(buffer, 0);
        }
        /// 
        /// Reading bytes
        /// 
        /// 
        public async Task ReadBytesAsync()
        {
            var length = BitConverter.ToInt32(await ReadBufferAsync(4), 0);
            if (length == 0) return new byte[0];
            return ReadBuffer(length);
        }
        public async Task ReadShortAsync()
        {
            var buffer = await ReadBufferAsync(2);
            return BitConverter.ToInt16(buffer, 0);
        }
        public async Task ReadUShortAsync()
        {
            var buffer = await ReadBufferAsync(2);
            return BitConverter.ToUInt16(buffer, 0);
        }
        /// 
        /// Read 32-bit integer (4 bytes)
        /// 
        public async Task ReadInt32Async()
        {
            var buffer = await ReadBufferAsync(4);
            return BitConverter.ToInt32(buffer, 0);
        }
        public async Task ReadUInt32Async()
        {
            var buffer = await ReadBufferAsync(4);
            return BitConverter.ToUInt32(buffer, 0);
        }
        public async Task ReadDecimalAsync()
        {
            var arr = await ReadBufferAsync(16);
            var p1 = BitConverter.ToInt32(arr, 0);
            var p2 = BitConverter.ToInt32(arr, 4);
            var p3 = BitConverter.ToInt32(arr, 8);
            var p4 = BitConverter.ToInt32(arr, 12);
            return BitConverterExt.ToDecimal(new int[] { p1, p2, p3, p4 });
        }
        /// 
        /// Read integer 64-bit number (8 bytes)
        /// 
        public async Task ReadLongAsync()
        {
            var buffer = await ReadBufferAsync(8);
            return BitConverter.ToInt64(buffer, 0);
        }
        public async Task ReadULongAsync()
        {
            var buffer = await ReadBufferAsync(8);
            return BitConverter.ToUInt64(buffer, 0);
        }
        public async Task ReadTimeSpanAsync()
        {
            return new TimeSpan(await ReadLongAsync());
        }
        public async Task ReadFloatAsync()
        {
            var buffer = await ReadBufferAsync(4);
            return BitConverter.ToSingle(buffer, 0);
        }
        public async Task ReadDoubleAsync()
        {
            var buffer = await ReadBufferAsync(8);
            return BitConverter.ToDouble(buffer, 0);
        }
        /// 
        /// Read string (4 bytes per length + Length bytes)
        /// 
        public async Task ReadStringAsync()
        {
            var length = BitConverter.ToInt32(await ReadBufferAsync(4), 0);
            if (length == 0) return null;
            var buffer = await ReadBufferAsync(length);
            return Encoding.UTF8.GetString(buffer);
        }
        /// 
        /// Read GUID (16 bytes)
        /// 
        public async Task ReadGuidAsync()
        {
            var buffer = await ReadBufferAsync(16);
            return new Guid(buffer);
        }
        /// 
        /// Reading the datetime
        /// 
        /// 
        public async Task ReadDateTimeAsync()
        {
            var is_null = ReadByte();
            if (is_null == 0) return null;
            var buffer = await ReadBufferAsync(8);
            long deserialized = BitConverter.ToInt64(buffer, 0);
            return DateTime.FromBinary(deserialized);
        }
        public async Task ReadIPAsync()
        {
            var exists = await ReadByteAsync();
            if (exists == 1)
            {
                var addr = await ReadBytesAsync();
                return new IPAddress(addr);
            }
            return null;
        }
        public async Task ReadIPEndpointAsync()
        {
            var exists = await ReadByteAsync();
            if (exists == 1)
            {
                var addr = await ReadIPAsync();
                var port = await ReadInt32Async();
                return new IPEndPoint(addr, port);
            }
            return null;
        }
        #region Extensions
        #region Collections
        private async Task> ReadListAsync(Func> readAsync, Func read)
        {
            int count = await ReadInt32Async();
            var collection = new List(count);
            if (count > 0)
            {
                if (_accessor.IsMemoryStream)
                {
                    for (int i = 0; i < count; i++)
                    {
                        collection.Add(read.Invoke());
                    }
                }
                else
                {
                    for (int i = 0; i < count; i++)
                    {
                        collection.Add(await readAsync.Invoke());
                    }
                }
            }
            return collection;
        }
        public async Task> ReadCollectionAsync()
            where T : IAsyncBinarySerializable, new()
        {
            int count = await ReadInt32Async();
            var collection = new List(count);
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    var item = new T();
                    await item.DeserializeAsync(this);
                    collection.Add(item);
                }
            }
            return collection;
        }
        public async Task> ReadStringCollectionAsync() => await ReadListAsync(ReadStringAsync, ReadString);
        public async Task> ReadIPCollectionAsync() => await ReadListAsync(ReadIPAsync, ReadIP);
        public async Task> ReadIPEndPointCollectionAsync() => await ReadListAsync(ReadIPEndpointAsync, ReadIPEndpoint);
        public async Task> ReadGuidCollectionAsync() => await ReadListAsync(ReadGuidAsync, ReadGuid);
        public async Task> ReadDateTimeCollectionAsync() => await ReadListAsync(ReadDateTimeAsync, ReadDateTime);
        public async Task> ReadInt64CollectionAsync() => await ReadListAsync(ReadLongAsync, ReadLong);
        public async Task> ReadInt32CollectionAsync() => await ReadListAsync(ReadInt32Async, ReadInt32);
        public async Task> ReadUInt64CollectionAsync() => await ReadListAsync(ReadULongAsync, ReadULong);
        public async Task> ReadUInt32CollectionAsync() => await ReadListAsync(ReadUInt32Async, ReadUInt32);
        public async Task> ReadCharCollectionAsync() => await ReadListAsync(ReadCharAsync, ReadChar);
        public async Task> ReadShortCollectionAsync() => await ReadListAsync(ReadShortAsync, ReadShort);
        public async Task> ReadUShortCollectionAsync() => await ReadListAsync(ReadUShortAsync, ReadUShort);
        public async Task> ReadFloatCollectionAsync() => await ReadListAsync(ReadFloatAsync, ReadFloat);
        public async Task> ReadDoubleCollectionAsync() => await ReadListAsync(ReadDoubleAsync, ReadDouble);
        public async Task> ReadBooleanCollectionAsync() => await ReadListAsync(ReadBooleanAsync, ReadBoolean);
        public async Task> ReadByteCollectionAsync() => await ReadListAsync(ReadByteAsync, ReadByte);
        public async Task> ReadByteArrayCollectionAsync() => await ReadListAsync(ReadBytesAsync, ReadBytes);
        public async Task> ReadDecimalCollectionAsync() => await ReadListAsync(ReadDecimalAsync, ReadDecimal);
        public async Task> ReadTimeSpanCollectionAsync() => await ReadListAsync(ReadTimeSpanAsync, ReadTimeSpan);
        #endregion
        #region Arrays
        private async Task ReadArrayAsync(Func> readAsync, Func read)
        {
            int count = await ReadInt32Async();
            var array = new T[count];
            if (count > 0)
            {
                if (_accessor.IsMemoryStream)
                {
                    for (int i = 0; i < count; i++)
                    {
                        array[i] = read.Invoke();
                    }
                }
                else
                {
                    for (int i = 0; i < count; i++)
                    {
                        array[i] = await readAsync.Invoke();
                    }
                }
            }
            return array;
        }
        public async Task ReadArrayAsync()
            where T : IAsyncBinarySerializable, new()
        {
            int count = ReadInt32();
            var array = new T[count];
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    var item = new T();
                    await item.DeserializeAsync(this);
                    array[i] = item;
                }
            }
            return array;
        }
        public async Task ReadStringArrayAsync() => await ReadArrayAsync(ReadStringAsync, ReadString);
        public async Task ReadIPArrayAsync() => await ReadArrayAsync(ReadIPAsync, ReadIP);
        public async Task ReadIPEndPointArrayAsync() => await ReadArrayAsync(ReadIPEndpointAsync, ReadIPEndpoint);
        public async Task ReadGuidArrayAsync() => await ReadArrayAsync(ReadGuidAsync, ReadGuid);
        public async Task ReadDateTimeArrayAsync() => await ReadArrayAsync(ReadDateTimeAsync, ReadDateTime);
        public async Task ReadInt64ArrayAsync() => await ReadArrayAsync(ReadLongAsync, ReadLong);
        public async Task ReadInt32ArrayAsync() => await ReadArrayAsync(ReadInt32Async, ReadInt32);
        public async Task ReadUInt64ArrayAsync() => await ReadArrayAsync(ReadULongAsync, ReadULong);
        public async Task ReadUInt32ArrayAsync() => await ReadArrayAsync(ReadUInt32Async, ReadUInt32);
        public async Task ReadCharArrayAsync() => await ReadArrayAsync(ReadCharAsync, ReadChar);
        public async Task ReadShortArrayAsync() => await ReadArrayAsync(ReadShortAsync, ReadShort);
        public async Task ReadUShortArrayAsync() => await ReadArrayAsync(ReadUShortAsync, ReadUShort);
        public async Task ReadFloatArrayAsync() => await ReadArrayAsync(ReadFloatAsync, ReadFloat);
        public async Task ReadDoubleArrayAsync() => await ReadArrayAsync(ReadDoubleAsync, ReadDouble);
        public async Task ReadBooleanArrayAsync() => await ReadArrayAsync(ReadBooleanAsync, ReadBoolean);
        public async Task ReadByteArrayAsync()
        {
            if (_accessor.IsMemoryStream)
            {
                return ReadBytes();
            }
            return await ReadBytesAsync();
        }
        public async Task ReadByteArrayArrayAsync() => await ReadArrayAsync(ReadBytesAsync, ReadBytes);
        public async Task ReadDecimalArrayAsync() => await ReadArrayAsync(ReadDecimalAsync, ReadDecimal);
        public async Task ReadTimeSpanArrayAsync() => await ReadArrayAsync(ReadTimeSpanAsync, ReadTimeSpan);
        #endregion
        public async Task> ReadDictionaryAsync()
        {
            int count = ReadInt32();
            var collection = new Dictionary(count);
            if (count > 0)
            {
                TKey key;
                TValue value;
                for (int i = 0; i < count; i++)
                {
                    key = await ReadCompatibleAsync();
                    value = await ReadCompatibleAsync();
                    collection.Add(key, value);
                }
            }
            return collection;
        }
        public async Task> ReadDictionaryAsConcurrentAsync()
        {
            int count = ReadInt32();
            var collection = new ConcurrentDictionary();
            if (count > 0)
            {
                TKey key;
                TValue value;
                for (int i = 0; i < count; i++)
                {
                    key = await ReadCompatibleAsync();
                    value = await ReadCompatibleAsync();
                    collection.TryAdd(key, value);
                }
            }
            return collection;
        }
        public async Task ReadCompatibleAsync()
        {
            return await MessageSerializer.DeserializeCompatibleAsync(this);
        }
        public async Task ReadAsync() where T : IAsyncBinarySerializable
        {
            byte type = await ReadByteAsync();
            if (type == 0) return default(T);
            var item = (T)Activator.CreateInstance();
            await item.DeserializeAsync(this);
            return item;
        }
        public async Task ReadAsync(object arg) where T : IAsyncBinarySerializable
        {
            byte type = ReadByte();
            if (type == 0) return default(T);
            var item = (T)Activator.CreateInstance(typeof(T), arg);
            await item.DeserializeAsync(this);
            return item;
        }
        #endregion Extensions
    }
}