THRIFT-4879 general performance improvements for netstd library
Client: netstd
Patch: Jens Geyer

This closes #1808
diff --git a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
index 7a0243a..3f30d4a 100644
--- a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
@@ -27,16 +27,19 @@
     // ReSharper disable once InconsistentNaming
     public class TBinaryProtocol : TProtocol
     {
-        //TODO: Unit tests
-        //TODO: Localization
-        //TODO: pragma
-
         protected const uint VersionMask = 0xffff0000;
         protected const uint Version1 = 0x80010000;
 
         protected bool StrictRead;
         protected bool StrictWrite;
 
+        // minimize memory allocations by means of an preallocated bytes buffer
+        // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
+        private byte[] PreAllocatedBuffer = new byte[128];
+
+        private static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
+        private static readonly TField StopField = new TField() { Type = TType.Stop };
+
         public TBinaryProtocol(TTransport trans)
             : this(trans, false, true)
         {
@@ -131,12 +134,15 @@
                 return;
             }
 
-            await WriteByteAsync((sbyte) map.KeyType, cancellationToken);
-            await WriteByteAsync((sbyte) map.ValueType, cancellationToken);
+            PreAllocatedBuffer[0] = (byte)map.KeyType;
+            PreAllocatedBuffer[1] = (byte)map.ValueType;
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
+
             await WriteI32Async(map.Count, cancellationToken);
         }
 
         public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -192,15 +198,6 @@
             await WriteByteAsync(b ? (sbyte) 1 : (sbyte) 0, cancellationToken);
         }
 
-        protected internal static byte[] CreateWriteByte(sbyte b)
-        {
-            var bout = new byte[1];
-
-            bout[0] = (byte) b;
-
-            return bout;
-        }
-
         public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -208,20 +205,10 @@
                 return;
             }
 
-            var bout = CreateWriteByte(b);
-            await Trans.WriteAsync(bout, 0, 1, cancellationToken);
+            PreAllocatedBuffer[0] = (byte)b;
+
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
         }
-
-        protected internal static byte[] CreateWriteI16(short s)
-        {
-            var i16Out = new byte[2];
-
-            i16Out[0] = (byte) (0xff & (s >> 8));
-            i16Out[1] = (byte) (0xff & s);
-
-            return i16Out;
-        }
-
         public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -229,20 +216,10 @@
                 return;
             }
 
-            var i16Out = CreateWriteI16(i16);
-            await Trans.WriteAsync(i16Out, 0, 2, cancellationToken);
-        }
+            PreAllocatedBuffer[0] = (byte)(0xff & (i16 >> 8));
+            PreAllocatedBuffer[1] = (byte)(0xff & i16);
 
-        protected internal static byte[] CreateWriteI32(int i32)
-        {
-            var i32Out = new byte[4];
-
-            i32Out[0] = (byte) (0xff & (i32 >> 24));
-            i32Out[1] = (byte) (0xff & (i32 >> 16));
-            i32Out[2] = (byte) (0xff & (i32 >> 8));
-            i32Out[3] = (byte) (0xff & i32);
-
-            return i32Out;
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
         }
 
         public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
@@ -252,26 +229,15 @@
                 return;
             }
 
-            var i32Out = CreateWriteI32(i32);
-            await Trans.WriteAsync(i32Out, 0, 4, cancellationToken);
+            PreAllocatedBuffer[0] = (byte)(0xff & (i32 >> 24));
+            PreAllocatedBuffer[1] = (byte)(0xff & (i32 >> 16));
+            PreAllocatedBuffer[2] = (byte)(0xff & (i32 >> 8));
+            PreAllocatedBuffer[3] = (byte)(0xff & i32);
+
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 4, cancellationToken);
         }
 
-        protected internal static byte[] CreateWriteI64(long i64)
-        {
-            var i64Out = new byte[8];
-
-            i64Out[0] = (byte) (0xff & (i64 >> 56));
-            i64Out[1] = (byte) (0xff & (i64 >> 48));
-            i64Out[2] = (byte) (0xff & (i64 >> 40));
-            i64Out[3] = (byte) (0xff & (i64 >> 32));
-            i64Out[4] = (byte) (0xff & (i64 >> 24));
-            i64Out[5] = (byte) (0xff & (i64 >> 16));
-            i64Out[6] = (byte) (0xff & (i64 >> 8));
-            i64Out[7] = (byte) (0xff & i64);
-
-            return i64Out;
-        }
-
+      
         public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -279,8 +245,16 @@
                 return;
             }
 
-            var i64Out = CreateWriteI64(i64);
-            await Trans.WriteAsync(i64Out, 0, 8, cancellationToken);
+            PreAllocatedBuffer[0] = (byte)(0xff & (i64 >> 56));
+            PreAllocatedBuffer[1] = (byte)(0xff & (i64 >> 48));
+            PreAllocatedBuffer[2] = (byte)(0xff & (i64 >> 40));
+            PreAllocatedBuffer[3] = (byte)(0xff & (i64 >> 32));
+            PreAllocatedBuffer[4] = (byte)(0xff & (i64 >> 24));
+            PreAllocatedBuffer[5] = (byte)(0xff & (i64 >> 16));
+            PreAllocatedBuffer[6] = (byte)(0xff & (i64 >> 8));
+            PreAllocatedBuffer[7] = (byte)(0xff & i64);
+
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
         }
 
         public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
@@ -293,6 +267,7 @@
             await WriteI64Async(BitConverter.DoubleToInt64Bits(d), cancellationToken);
         }
 
+
         public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -304,7 +279,7 @@
             await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
         }
 
-        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -332,7 +307,7 @@
                     throw new TProtocolException(TProtocolException.BAD_VERSION,
                         "Missing version in ReadMessageBegin, old client?");
                 }
-                message.Name = await ReadStringBodyAsync(size, cancellationToken);
+                message.Name = (size > 0) ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty;
                 message.Type = (TMessageType) await ReadByteAsync(cancellationToken);
                 message.SeqID = await ReadI32Async(cancellationToken);
             }
@@ -347,15 +322,14 @@
             }
         }
 
-        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 await Task.FromCanceled(cancellationToken);
             }
 
-            //TODO: no read from internal transport?
-            return new TStruct();
+            return AnonymousStruct;
         }
 
         public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
@@ -366,24 +340,24 @@
             }
         }
 
-        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<TField>(cancellationToken);
             }
 
-            var field = new TField
-            {
-                Type = (TType) await ReadByteAsync(cancellationToken)
-            };
 
-            if (field.Type != TType.Stop)
+            var type = (TType)await ReadByteAsync(cancellationToken);
+            if (type == TType.Stop)
             {
-                field.ID = await ReadI16Async(cancellationToken);
+                return StopField;
             }
 
-            return field;
+            return new TField {
+                Type = type,
+                ID = await ReadI16Async(cancellationToken)
+            };
         }
 
         public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
@@ -394,7 +368,7 @@
             }
         }
 
-        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -419,7 +393,7 @@
             }
         }
 
-        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -443,7 +417,7 @@
             }
         }
 
-        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -467,7 +441,7 @@
             }
         }
 
-        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        public override async ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -477,82 +451,78 @@
             return await ReadByteAsync(cancellationToken) == 1;
         }
 
-        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<sbyte>(cancellationToken);
             }
 
-            var bin = new byte[1];
-            await Trans.ReadAllAsync(bin, 0, 1, cancellationToken); //TODO: why readall ?
-            return (sbyte) bin[0];
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
+            return (sbyte)PreAllocatedBuffer[0];
         }
 
-        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<short>(cancellationToken);
             }
 
-            var i16In = new byte[2];
-            await Trans.ReadAllAsync(i16In, 0, 2, cancellationToken);
-            var result = (short) (((i16In[0] & 0xff) << 8) | i16In[1] & 0xff);
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
+            var result = (short) (((PreAllocatedBuffer[0] & 0xff) << 8) | PreAllocatedBuffer[1] & 0xff);
             return result;
         }
 
-        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<int>(cancellationToken);
             }
 
-            var i32In = new byte[4];
-            await Trans.ReadAllAsync(i32In, 0, 4, cancellationToken);
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 4, cancellationToken);
 
             var result = 
-                ((i32In[0] & 0xff) << 24) | 
-                ((i32In[1] & 0xff) << 16) | 
-                ((i32In[2] & 0xff) << 8) |
-                i32In[3] & 0xff;
+                ((PreAllocatedBuffer[0] & 0xff) << 24) | 
+                ((PreAllocatedBuffer[1] & 0xff) << 16) | 
+                ((PreAllocatedBuffer[2] & 0xff) << 8) |
+                PreAllocatedBuffer[3] & 0xff;
 
             return result;
         }
 
 #pragma warning disable 675
 
-        protected internal long CreateReadI64(byte[] buf)
+        protected internal long ReadI64FromPreAllocatedBuffer()
         {
             var result =
-                ((long) (buf[0] & 0xff) << 56) |
-                ((long) (buf[1] & 0xff) << 48) |
-                ((long) (buf[2] & 0xff) << 40) |
-                ((long) (buf[3] & 0xff) << 32) |
-                ((long) (buf[4] & 0xff) << 24) |
-                ((long) (buf[5] & 0xff) << 16) |
-                ((long) (buf[6] & 0xff) << 8) |
-                buf[7] & 0xff;
+                ((long) (PreAllocatedBuffer[0] & 0xff) << 56) |
+                ((long) (PreAllocatedBuffer[1] & 0xff) << 48) |
+                ((long) (PreAllocatedBuffer[2] & 0xff) << 40) |
+                ((long) (PreAllocatedBuffer[3] & 0xff) << 32) |
+                ((long) (PreAllocatedBuffer[4] & 0xff) << 24) |
+                ((long) (PreAllocatedBuffer[5] & 0xff) << 16) |
+                ((long) (PreAllocatedBuffer[6] & 0xff) << 8) |
+                PreAllocatedBuffer[7] & 0xff;
 
             return result;
         }
 
 #pragma warning restore 675
 
-        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<long>(cancellationToken);
             }
 
-            var i64In = new byte[8];
-            await Trans.ReadAllAsync(i64In, 0, 8, cancellationToken);
-            return CreateReadI64(i64In);
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
+            return ReadI64FromPreAllocatedBuffer();
         }
 
-        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -563,7 +533,7 @@
             return BitConverter.Int64BitsToDouble(d);
         }
 
-        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -576,13 +546,30 @@
             return buf;
         }
 
-        private async Task<string> ReadStringBodyAsync(int size, CancellationToken cancellationToken)
+        public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<string>(cancellationToken);
+            }
+
+            var size = await ReadI32Async(cancellationToken);
+            return size > 0 ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty;
+        }
+
+        private async ValueTask<string> ReadStringBodyAsync(int size, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 await Task.FromCanceled<string>(cancellationToken);
             }
 
+            if (size <= PreAllocatedBuffer.Length)
+            {
+                await Trans.ReadAllAsync(PreAllocatedBuffer, 0, size, cancellationToken);
+                return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, size);
+            }
+
             var buf = new byte[size];
             await Trans.ReadAllAsync(buf, 0, size, cancellationToken);
             return Encoding.UTF8.GetString(buf, 0, buf.Length);
diff --git a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
index e6c5dbd..c26633a 100644
--- a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
@@ -17,6 +17,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -37,10 +38,13 @@
         private const byte TypeBits = 0x07; // 0000 0111
         private const int TypeShiftAmount = 5;
         private static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
-        private static readonly TField Tstop = new TField(string.Empty, TType.Stop, 0);
+        private static readonly TField StopField = new TField(string.Empty, TType.Stop, 0);
+
+        private const byte NoTypeOverride = 0xFF;
 
         // ReSharper disable once InconsistentNaming
         private static readonly byte[] TTypeToCompactType = new byte[16];
+        private static readonly TType[] CompactTypeToTType = new TType[13];
 
         /// <summary>
         ///     Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
@@ -59,6 +63,26 @@
 
         private short _lastFieldId;
 
+        // minimize memory allocations by means of an preallocated bytes buffer
+        // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
+        private byte[] PreAllocatedBuffer = new byte[128]; 
+
+        private struct VarInt
+        {
+            public byte[] bytes;
+            public int count;
+        }
+
+        // minimize memory allocations by means of an preallocated VarInt buffer
+        private VarInt PreAllocatedVarInt = new VarInt()
+        {
+            bytes = new byte[10], // see Int64ToVarInt()
+            count = 0
+        };
+
+
+
+
         public TCompactProtocol(TTransport trans)
             : base(trans)
         {
@@ -74,6 +98,20 @@
             TTypeToCompactType[(int) TType.Set] = Types.Set;
             TTypeToCompactType[(int) TType.Map] = Types.Map;
             TTypeToCompactType[(int) TType.Struct] = Types.Struct;
+
+            CompactTypeToTType[Types.Stop] = TType.Stop;
+            CompactTypeToTType[Types.BooleanTrue] = TType.Bool;
+            CompactTypeToTType[Types.BooleanFalse] = TType.Bool;
+            CompactTypeToTType[Types.Byte] = TType.Byte;
+            CompactTypeToTType[Types.I16] = TType.I16;
+            CompactTypeToTType[Types.I32] = TType.I32;
+            CompactTypeToTType[Types.I64] = TType.I64;
+            CompactTypeToTType[Types.Double] = TType.Double;
+            CompactTypeToTType[Types.Binary] = TType.String;
+            CompactTypeToTType[Types.List] = TType.List;
+            CompactTypeToTType[Types.Set] = TType.Set;
+            CompactTypeToTType[Types.Map] = TType.Map;
+            CompactTypeToTType[Types.Struct] = TType.Struct;
         }
 
         public void Reset()
@@ -84,19 +122,12 @@
 
         public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
         {
-            if (cancellationToken.IsCancellationRequested)
-            {
-                return;
-            }
+            PreAllocatedBuffer[0] = ProtocolId;
+            PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask));
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
 
-            await Trans.WriteAsync(new[] {ProtocolId}, cancellationToken);
-            await
-                Trans.WriteAsync(
-                    new[] {(byte) ((Version & VersionMask) | (((uint) message.Type << TypeShiftAmount) & TypeMask))},
-                    cancellationToken);
-
-            var bufferTuple = CreateWriteVarInt32((uint) message.SeqID);
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int32ToVarInt((uint) message.SeqID, ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
 
             await WriteStringAsync(message.Name, cancellationToken);
         }
@@ -135,26 +166,31 @@
             _lastFieldId = _lastField.Pop();
         }
 
-        private async Task WriteFieldBeginInternalAsync(TField field, byte typeOverride,
-            CancellationToken cancellationToken)
+        private async Task WriteFieldBeginInternalAsync(TField field, byte fieldType, CancellationToken cancellationToken)
         {
-            // if there's a exType override, use that.
-            var typeToWrite = typeOverride == 0xFF ? GetCompactType(field.Type) : typeOverride;
+            // if there's a exType override passed in, use that. Otherwise ask GetCompactType().
+            if (fieldType == NoTypeOverride)
+                fieldType = GetCompactType(field.Type);
+
 
             // check if we can use delta encoding for the field id
-            if ((field.ID > _lastFieldId) && (field.ID - _lastFieldId <= 15))
+            if (field.ID > _lastFieldId)
             {
-                var b = (byte) (((field.ID - _lastFieldId) << 4) | typeToWrite);
-                // Write them together
-                await Trans.WriteAsync(new[] {b}, cancellationToken);
-            }
-            else
-            {
-                // Write them separate
-                await Trans.WriteAsync(new[] {typeToWrite}, cancellationToken);
-                await WriteI16Async(field.ID, cancellationToken);
+                var delta = field.ID - _lastFieldId;
+                if (delta <= 15)
+                {
+                    // Write them together
+                    PreAllocatedBuffer[0] = (byte)((delta << 4) | fieldType);
+                    await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
+                    _lastFieldId = field.ID;
+                    return;
+                }
             }
 
+            // Write them separate
+            PreAllocatedBuffer[0] = fieldType;
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
+            await WriteI16Async(field.ID, cancellationToken);
             _lastFieldId = field.ID;
         }
 
@@ -166,7 +202,7 @@
             }
             else
             {
-                await WriteFieldBeginInternalAsync(field, 0xFF, cancellationToken);
+                await WriteFieldBeginInternalAsync(field, NoTypeOverride, cancellationToken);
             }
         }
 
@@ -185,7 +221,8 @@
                 return;
             }
 
-            await Trans.WriteAsync(new[] {Types.Stop}, cancellationToken);
+            PreAllocatedBuffer[0] = Types.Stop;
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
         }
 
         protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken)
@@ -202,14 +239,16 @@
 
             if (size <= 14)
             {
-                await Trans.WriteAsync(new[] {(byte) ((size << 4) | GetCompactType(elemType))}, cancellationToken);
+                PreAllocatedBuffer[0] = (byte)((size << 4) | GetCompactType(elemType));
+                await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
             }
             else
             {
-                await Trans.WriteAsync(new[] {(byte) (0xf0 | GetCompactType(elemType))}, cancellationToken);
+                PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(elemType));
+                await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
 
-                var bufferTuple = CreateWriteVarInt32((uint) size);
-                await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+                Int32ToVarInt((uint) size, ref PreAllocatedVarInt);
+                await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
             }
         }
 
@@ -261,15 +300,15 @@
             if (_booleanField != null)
             {
                 // we haven't written the field header yet
-                await
-                    WriteFieldBeginInternalAsync(_booleanField.Value, b ? Types.BooleanTrue : Types.BooleanFalse,
-                        cancellationToken);
+                var type = b ? Types.BooleanTrue : Types.BooleanFalse;
+                await WriteFieldBeginInternalAsync(_booleanField.Value, type, cancellationToken);
                 _booleanField = null;
             }
             else
             {
-                // we're not part of a field, so just Write the value.
-                await Trans.WriteAsync(new[] {b ? Types.BooleanTrue : Types.BooleanFalse}, cancellationToken);
+                // we're not part of a field, so just write the value.
+                PreAllocatedBuffer[0] = b ? Types.BooleanTrue : Types.BooleanFalse;
+                await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
             }
         }
 
@@ -280,7 +319,8 @@
                 return;
             }
 
-            await Trans.WriteAsync(new[] {(byte) b}, cancellationToken);
+            PreAllocatedBuffer[0] = (byte)b;
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
         }
 
         public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
@@ -290,29 +330,27 @@
                 return;
             }
 
-            var bufferTuple = CreateWriteVarInt32(IntToZigzag(i16));
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int32ToVarInt(IntToZigzag(i16), ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
         }
 
-        protected internal Tuple<byte[], int> CreateWriteVarInt32(uint n)
+        private static void Int32ToVarInt(uint n, ref VarInt varint)
         {
-            // Write an i32 as a varint.Results in 1 - 5 bytes on the wire.
-            var i32Buf = new byte[5];
-            var idx = 0;
+            // Write an i32 as a varint. Results in 1 - 5 bytes on the wire.
+            varint.count = 0;
+            Debug.Assert(varint.bytes.Length >= 5);
 
             while (true)
             {
                 if ((n & ~0x7F) == 0)
                 {
-                    i32Buf[idx++] = (byte) n;
+                    varint.bytes[varint.count++] = (byte)n;
                     break;
                 }
 
-                i32Buf[idx++] = (byte) ((n & 0x7F) | 0x80);
+                varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
                 n >>= 7;
             }
-
-            return new Tuple<byte[], int>(i32Buf, idx);
         }
 
         public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
@@ -322,28 +360,26 @@
                 return;
             }
 
-            var bufferTuple = CreateWriteVarInt32(IntToZigzag(i32));
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int32ToVarInt(IntToZigzag(i32), ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
         }
 
-        protected internal Tuple<byte[], int> CreateWriteVarInt64(ulong n)
+        static private void Int64ToVarInt(ulong n, ref VarInt varint)
         {
             // Write an i64 as a varint. Results in 1-10 bytes on the wire.
-            var buf = new byte[10];
-            var idx = 0;
+            varint.count = 0;
+            Debug.Assert(varint.bytes.Length >= 10);
 
             while (true)
             {
-                if ((n & ~(ulong) 0x7FL) == 0)
+                if ((n & ~(ulong)0x7FL) == 0)
                 {
-                    buf[idx++] = (byte) n;
+                    varint.bytes[varint.count++] = (byte)n;
                     break;
                 }
-                buf[idx++] = (byte) ((n & 0x7F) | 0x80);
+                varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
                 n >>= 7;
             }
-
-            return new Tuple<byte[], int>(buf, idx);
         }
 
         public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
@@ -353,8 +389,8 @@
                 return;
             }
 
-            var bufferTuple = CreateWriteVarInt64(LongToZigzag(i64));
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int64ToVarInt(LongToZigzag(i64), ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
         }
 
         public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
@@ -364,9 +400,8 @@
                 return;
             }
 
-            var data = new byte[8];
-            FixedLongToBytes(BitConverter.DoubleToInt64Bits(d), data, 0);
-            await Trans.WriteAsync(data, cancellationToken);
+            FixedLongToBytes(BitConverter.DoubleToInt64Bits(d), PreAllocatedBuffer, 0);
+            await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
         }
 
         public override async Task WriteStringAsync(string str, CancellationToken cancellationToken)
@@ -378,8 +413,8 @@
 
             var bytes = Encoding.UTF8.GetBytes(str);
 
-            var bufferTuple = CreateWriteVarInt32((uint) bytes.Length);
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int32ToVarInt((uint) bytes.Length, ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
             await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
         }
 
@@ -390,8 +425,8 @@
                 return;
             }
 
-            var bufferTuple = CreateWriteVarInt32((uint) bytes.Length);
-            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            Int32ToVarInt((uint) bytes.Length, ref PreAllocatedVarInt);
+            await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
             await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
         }
 
@@ -401,19 +436,19 @@
             {
                 return;
             }
-
+            
             if (map.Count == 0)
             {
-                await Trans.WriteAsync(new[] {(byte) 0}, cancellationToken);
+                PreAllocatedBuffer[0] = 0;
+                await Trans.WriteAsync( PreAllocatedBuffer, 0, 1, cancellationToken);
             }
             else
             {
-                var bufferTuple = CreateWriteVarInt32((uint) map.Count);
-                await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
-                await
-                    Trans.WriteAsync(
-                        new[] {(byte) ((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType))},
-                        cancellationToken);
+                Int32ToVarInt((uint) map.Count, ref PreAllocatedVarInt);
+                await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
+
+                PreAllocatedBuffer[0] = (byte)((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType));
+                await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
             }
         }
 
@@ -425,7 +460,7 @@
             }
         }
 
-        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -461,7 +496,7 @@
             }
         }
 
-        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -492,19 +527,23 @@
             _lastFieldId = _lastField.Pop();
         }
 
-        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
         {
             // Read a field header off the wire.
             var type = (byte) await ReadByteAsync(cancellationToken);
+
             // if it's a stop, then we can return immediately, as the struct is over.
             if (type == Types.Stop)
             {
-                return Tstop;
+                return StopField;
             }
 
-            short fieldId;
+
             // mask off the 4 MSB of the exType header. it could contain a field id delta.
             var modifier = (short) ((type & 0xf0) >> 4);
+            var compactType = (byte)(type & 0x0f);
+
+            short fieldId;
             if (modifier == 0)
             {
                 fieldId = await ReadI16Async(cancellationToken);
@@ -514,11 +553,13 @@
                 fieldId = (short) (_lastFieldId + modifier);
             }
 
-            var field = new TField(string.Empty, GetTType((byte) (type & 0x0f)), fieldId);
+            var ttype = GetTType(compactType);
+            var field = new TField(string.Empty, ttype, fieldId);
+
             // if this happens to be a boolean field, the value is encoded in the exType
-            if (IsBoolType(type))
+            if( ttype == TType.Bool)
             {
-                _boolValue = (byte) (type & 0x0f) == Types.BooleanTrue;
+                _boolValue = (compactType == Types.BooleanTrue);
             }
 
             // push the new field onto the field stack so we can keep the deltas going.
@@ -534,7 +575,7 @@
             }
         }
 
-        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -560,7 +601,7 @@
             }
         }
 
-        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
         {
             /*
             Read a set header off the wire. If the set size is 0-14, the size will
@@ -572,13 +613,8 @@
             return new TSet(await ReadListBeginAsync(cancellationToken));
         }
 
-        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        public override ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
         {
-            if (cancellationToken.IsCancellationRequested)
-            {
-                return await Task.FromCanceled<bool>(cancellationToken);
-            }
-
             /*
             Read a boolean off the wire. If this is a boolean field, the value should
             already have been Read during ReadFieldBegin, so we'll just consume the
@@ -589,26 +625,27 @@
             {
                 var result = _boolValue.Value;
                 _boolValue = null;
-                return result;
+                return new ValueTask<bool>(result);
             }
 
-            return await ReadByteAsync(cancellationToken) == Types.BooleanTrue;
-        }
+            return InternalCall();
 
-        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
-        {
-            if (cancellationToken.IsCancellationRequested)
+            async ValueTask<bool> InternalCall()
             {
-                return await Task.FromCanceled<sbyte>(cancellationToken);
+                var data = await ReadByteAsync(cancellationToken);
+                return (data == Types.BooleanTrue);
             }
-
-            // Read a single byte off the wire. Nothing interesting here.
-            var buf = new byte[1];
-            await Trans.ReadAllAsync(buf, 0, 1, cancellationToken);
-            return (sbyte) buf[0];
         }
 
-        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+
+        public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            // Read a single byte off the wire. Nothing interesting here.
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
+            return (sbyte)PreAllocatedBuffer[0];
+        }
+
+        public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -618,7 +655,7 @@
             return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken));
         }
 
-        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -628,7 +665,7 @@
             return ZigzagToInt(await ReadVarInt32Async(cancellationToken));
         }
 
-        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -638,60 +675,55 @@
             return ZigzagToLong(await ReadVarInt64Async(cancellationToken));
         }
 
-        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
                 return await Task.FromCanceled<double>(cancellationToken);
             }
 
-            var longBits = new byte[8];
-            await Trans.ReadAllAsync(longBits, 0, 8, cancellationToken);
+            await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
 
-            return BitConverter.Int64BitsToDouble(BytesToLong(longBits));
+            return BitConverter.Int64BitsToDouble(BytesToLong(PreAllocatedBuffer));
         }
 
-        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
         {
-            if (cancellationToken.IsCancellationRequested)
-            {
-                await Task.FromCanceled<string>(cancellationToken);
-            }
-
-            // Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+            // read length
             var length = (int) await ReadVarInt32Async(cancellationToken);
-
             if (length == 0)
             {
                 return string.Empty;
             }
 
-            var buf = new byte[length];
-            await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
-
-            return Encoding.UTF8.GetString(buf);
-        }
-
-        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
-        {
-            if (cancellationToken.IsCancellationRequested)
+            // read and decode data
+            if (length < PreAllocatedBuffer.Length)
             {
-                return await Task.FromCanceled<byte[]>(cancellationToken);
+                await Trans.ReadAllAsync(PreAllocatedBuffer, 0, length, cancellationToken);
+                return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, length);
             }
 
-            // Read a byte[] from the wire.
+            var buf = new byte[length];
+            await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
+            return Encoding.UTF8.GetString(buf, 0, length);
+        }
+
+        public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            // read length
             var length = (int) await ReadVarInt32Async(cancellationToken);
             if (length == 0)
             {
                 return new byte[0];
             }
 
+            // read data
             var buf = new byte[length];
             await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
             return buf;
         }
 
-        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -739,7 +771,7 @@
         }
 
 
-        private async Task<uint> ReadVarInt32Async(CancellationToken cancellationToken)
+        private async ValueTask<uint> ReadVarInt32Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -768,7 +800,7 @@
             return result;
         }
 
-        private async Task<ulong> ReadVarInt64Async(CancellationToken cancellationToken)
+        private async ValueTask<ulong> ReadVarInt64Async(CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {
@@ -825,45 +857,10 @@
                 (bytes[0] & 0xffL);
         }
 
-        private static bool IsBoolType(byte b)
-        {
-            var lowerNibble = b & 0x0f;
-            return (lowerNibble == Types.BooleanTrue) || (lowerNibble == Types.BooleanFalse);
-        }
-
         private static TType GetTType(byte type)
         {
             // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
-            switch ((byte) (type & 0x0f))
-            {
-                case Types.Stop:
-                    return TType.Stop;
-                case Types.BooleanFalse:
-                case Types.BooleanTrue:
-                    return TType.Bool;
-                case Types.Byte:
-                    return TType.Byte;
-                case Types.I16:
-                    return TType.I16;
-                case Types.I32:
-                    return TType.I32;
-                case Types.I64:
-                    return TType.I64;
-                case Types.Double:
-                    return TType.Double;
-                case Types.Binary:
-                    return TType.String;
-                case Types.List:
-                    return TType.List;
-                case Types.Set:
-                    return TType.Set;
-                case Types.Map:
-                    return TType.Map;
-                case Types.Struct:
-                    return TType.Struct;
-                default:
-                    throw new TProtocolException($"Don't know what exType: {(byte) (type & 0x0f)}");
-            }
+            return CompactTypeToTType[type & 0x0f];
         }
 
         private static ulong LongToZigzag(long n)
diff --git a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
index 1298052..464bd62 100644
--- a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
@@ -396,7 +396,7 @@
         ///     Read in a JSON string, unescaping as appropriate.. Skip Reading from the
         ///     context if skipContext is true.
         /// </summary>
-        private async Task<byte[]> ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken)
+        private async ValueTask<byte[]> ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken)
         {
             using (var buffer = new MemoryStream())
             {
@@ -487,7 +487,7 @@
         ///     Read in a sequence of characters that are all valid in JSON numbers. Does
         ///     not do a complete regex check to validate that this is actually a number.
         /// </summary>
-        private async Task<string> ReadJsonNumericCharsAsync(CancellationToken cancellationToken)
+        private async ValueTask<string> ReadJsonNumericCharsAsync(CancellationToken cancellationToken)
         {
             var strbld = new StringBuilder();
             while (true)
@@ -514,7 +514,7 @@
         /// <summary>
         ///     Read in a JSON number. If the context dictates, Read in enclosing quotes.
         /// </summary>
-        private async Task<long> ReadJsonIntegerAsync(CancellationToken cancellationToken)
+        private async ValueTask<long> ReadJsonIntegerAsync(CancellationToken cancellationToken)
         {
             await Context.ReadConditionalDelimiterAsync(cancellationToken);
             if (Context.EscapeNumbers())
@@ -542,7 +542,7 @@
         ///     Read in a JSON double value. Throw if the value is not wrapped in quotes
         ///     when expected or if wrapped in quotes when not expected.
         /// </summary>
-        private async Task<double> ReadJsonDoubleAsync(CancellationToken cancellationToken)
+        private async ValueTask<double> ReadJsonDoubleAsync(CancellationToken cancellationToken)
         {
             await Context.ReadConditionalDelimiterAsync(cancellationToken);
             if (await Reader.PeekAsync(cancellationToken) == TJSONProtocolConstants.Quote[0])
@@ -578,7 +578,7 @@
         /// <summary>
         ///     Read in a JSON string containing base-64 encoded data and decode it.
         /// </summary>
-        private async Task<byte[]> ReadJsonBase64Async(CancellationToken cancellationToken)
+        private async ValueTask<byte[]> ReadJsonBase64Async(CancellationToken cancellationToken)
         {
             var b = await ReadJsonStringAsync(false, cancellationToken);
             var len = b.Length;
@@ -642,7 +642,7 @@
             PopContext();
         }
 
-        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             var message = new TMessage();
             await ReadJsonArrayStartAsync(cancellationToken);
@@ -663,7 +663,7 @@
             await ReadJsonArrayEndAsync(cancellationToken);
         }
 
-        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
         {
             await ReadJsonObjectStartAsync(cancellationToken);
             return new TStruct();
@@ -674,7 +674,7 @@
             await ReadJsonObjectEndAsync(cancellationToken);
         }
 
-        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
         {
             var field = new TField();
             var ch = await Reader.PeekAsync(cancellationToken);
@@ -696,7 +696,7 @@
             await ReadJsonObjectEndAsync(cancellationToken);
         }
 
-        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
         {
             var map = new TMap();
             await ReadJsonArrayStartAsync(cancellationToken);
@@ -713,7 +713,7 @@
             await ReadJsonArrayEndAsync(cancellationToken);
         }
 
-        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
         {
             var list = new TList();
             await ReadJsonArrayStartAsync(cancellationToken);
@@ -727,7 +727,7 @@
             await ReadJsonArrayEndAsync(cancellationToken);
         }
 
-        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
         {
             var set = new TSet();
             await ReadJsonArrayStartAsync(cancellationToken);
@@ -741,43 +741,43 @@
             await ReadJsonArrayEndAsync(cancellationToken);
         }
 
-        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        public override async ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
         {
             return await ReadJsonIntegerAsync(cancellationToken) != 0;
         }
 
-        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
         {
             return (sbyte) await ReadJsonIntegerAsync(cancellationToken);
         }
 
-        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
         {
             return (short) await ReadJsonIntegerAsync(cancellationToken);
         }
 
-        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
         {
             return (int) await ReadJsonIntegerAsync(cancellationToken);
         }
 
-        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
         {
             return await ReadJsonIntegerAsync(cancellationToken);
         }
 
-        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
         {
             return await ReadJsonDoubleAsync(cancellationToken);
         }
 
-        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
         {
             var buf = await ReadJsonStringAsync(false, cancellationToken);
             return Utf8Encoding.GetString(buf, 0, buf.Length);
         }
 
-        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
         {
             return await ReadJsonBase64Async(cancellationToken);
         }
@@ -938,7 +938,7 @@
             ///     Return and consume the next byte to be Read, either taking it from the
             ///     data buffer if present or getting it from the transport otherwise.
             /// </summary>
-            public async Task<byte> ReadAsync(CancellationToken cancellationToken)
+            public async ValueTask<byte> ReadAsync(CancellationToken cancellationToken)
             {
                 if (cancellationToken.IsCancellationRequested)
                 {
@@ -961,7 +961,7 @@
             ///     Return the next byte to be Read without consuming, filling the data
             ///     buffer if it has not been filled alReady.
             /// </summary>
-            public async Task<byte> PeekAsync(CancellationToken cancellationToken)
+            public async ValueTask<byte> PeekAsync(CancellationToken cancellationToken)
             {
                 if (cancellationToken.IsCancellationRequested)
                 {
@@ -972,8 +972,8 @@
                 {
                     // find more easy way to avoid exception on reading primitive types
                     await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken);
+                    _hasData = true;
                 }
-                _hasData = true;
                 return _data[0];
             }
         }
diff --git a/lib/netstd/Thrift/Protocol/TProtocol.cs b/lib/netstd/Thrift/Protocol/TProtocol.cs
index 1bc91eb..75edb11 100644
--- a/lib/netstd/Thrift/Protocol/TProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TProtocol.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -229,12 +229,12 @@
 
         public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken);
 
-        public virtual async Task<TMessage> ReadMessageBeginAsync()
+        public virtual async ValueTask<TMessage> ReadMessageBeginAsync()
         {
             return await ReadMessageBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadMessageEndAsync()
         {
@@ -243,12 +243,12 @@
 
         public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<TStruct> ReadStructBeginAsync()
+        public virtual async ValueTask<TStruct> ReadStructBeginAsync()
         {
             return await ReadStructBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadStructEndAsync()
         {
@@ -257,12 +257,12 @@
 
         public abstract Task ReadStructEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<TField> ReadFieldBeginAsync()
+        public virtual async ValueTask<TField> ReadFieldBeginAsync()
         {
             return await ReadFieldBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadFieldEndAsync()
         {
@@ -271,12 +271,12 @@
 
         public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<TMap> ReadMapBeginAsync()
+        public virtual async ValueTask<TMap> ReadMapBeginAsync()
         {
             return await ReadMapBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadMapEndAsync()
         {
@@ -285,12 +285,12 @@
 
         public abstract Task ReadMapEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<TList> ReadListBeginAsync()
+        public virtual async ValueTask<TList> ReadListBeginAsync()
         {
             return await ReadListBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TList> ReadListBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadListEndAsync()
         {
@@ -299,12 +299,12 @@
 
         public abstract Task ReadListEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<TSet> ReadSetBeginAsync()
+        public virtual async ValueTask<TSet> ReadSetBeginAsync()
         {
             return await ReadSetBeginAsync(CancellationToken.None);
         }
 
-        public abstract Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken);
 
         public virtual async Task ReadSetEndAsync()
         {
@@ -313,64 +313,64 @@
 
         public abstract Task ReadSetEndAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<bool> ReadBoolAsync()
+        public virtual async ValueTask<bool> ReadBoolAsync()
         {
             return await ReadBoolAsync(CancellationToken.None);
         }
 
-        public abstract Task<bool> ReadBoolAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<sbyte> ReadByteAsync()
+        public virtual async ValueTask<sbyte> ReadByteAsync()
         {
             return await ReadByteAsync(CancellationToken.None);
         }
 
-        public abstract Task<sbyte> ReadByteAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<short> ReadI16Async()
+        public virtual async ValueTask<short> ReadI16Async()
         {
             return await ReadI16Async(CancellationToken.None);
         }
 
-        public abstract Task<short> ReadI16Async(CancellationToken cancellationToken);
+        public abstract ValueTask<short> ReadI16Async(CancellationToken cancellationToken);
 
-        public virtual async Task<int> ReadI32Async()
+        public virtual async ValueTask<int> ReadI32Async()
         {
             return await ReadI32Async(CancellationToken.None);
         }
 
-        public abstract Task<int> ReadI32Async(CancellationToken cancellationToken);
+        public abstract ValueTask<int> ReadI32Async(CancellationToken cancellationToken);
 
-        public virtual async Task<long> ReadI64Async()
+        public virtual async ValueTask<long> ReadI64Async()
         {
             return await ReadI64Async(CancellationToken.None);
         }
 
-        public abstract Task<long> ReadI64Async(CancellationToken cancellationToken);
+        public abstract ValueTask<long> ReadI64Async(CancellationToken cancellationToken);
 
-        public virtual async Task<double> ReadDoubleAsync()
+        public virtual async ValueTask<double> ReadDoubleAsync()
         {
             return await ReadDoubleAsync(CancellationToken.None);
         }
 
-        public abstract Task<double> ReadDoubleAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken);
 
-        public virtual async Task<string> ReadStringAsync()
+        public virtual async ValueTask<string> ReadStringAsync()
         {
             return await ReadStringAsync(CancellationToken.None);
         }
 
-        public virtual async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        public virtual async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
         {
             var buf = await ReadBinaryAsync(cancellationToken);
             return Encoding.UTF8.GetString(buf, 0, buf.Length);
         }
 
-        public virtual async Task<byte[]> ReadBinaryAsync()
+        public virtual async ValueTask<byte[]> ReadBinaryAsync()
         {
             return await ReadBinaryAsync(CancellationToken.None);
         }
 
-        public abstract Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken);
+        public abstract ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken);
     }
-}
\ No newline at end of file
+}
diff --git a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
index c8a433d..845c827 100644
--- a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
+++ b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -144,7 +144,7 @@
             await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken);
         }
 
-        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken);
         }
@@ -154,7 +154,7 @@
             await _wrappedProtocol.ReadMessageEndAsync(cancellationToken);
         }
 
-        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken);
         }
@@ -164,7 +164,7 @@
             await _wrappedProtocol.ReadStructEndAsync(cancellationToken);
         }
 
-        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken);
         }
@@ -174,7 +174,7 @@
             await _wrappedProtocol.ReadFieldEndAsync(cancellationToken);
         }
 
-        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken);
         }
@@ -184,7 +184,7 @@
             await _wrappedProtocol.ReadMapEndAsync(cancellationToken);
         }
 
-        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadListBeginAsync(cancellationToken);
         }
@@ -194,7 +194,7 @@
             await _wrappedProtocol.ReadListEndAsync(cancellationToken);
         }
 
-        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken);
         }
@@ -204,44 +204,44 @@
             await _wrappedProtocol.ReadSetEndAsync(cancellationToken);
         }
 
-        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        public override async ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadBoolAsync(cancellationToken);
         }
 
-        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadByteAsync(cancellationToken);
         }
 
-        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadI16Async(cancellationToken);
         }
 
-        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadI32Async(cancellationToken);
         }
 
-        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadI64Async(cancellationToken);
         }
 
-        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadDoubleAsync(cancellationToken);
         }
 
-        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadStringAsync(cancellationToken);
         }
 
-        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadBinaryAsync(cancellationToken);
         }
     }
-}
\ No newline at end of file
+}