blob: 8e5d00d14f6a179e002cb564f2611cc254171ccd [file] [log] [blame]
Jens Geyer421444f2019-03-20 22:13:25 +01001// Licensed to the Apache Software Foundation(ASF) under one
Jens Geyeraa0c8b32019-01-28 23:27:45 +01002// or more contributor license agreements.See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18using System;
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +010019using System.Buffers;
zembord9d958a32019-11-21 13:11:44 +030020using System.Buffers.Binary;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010021using System.Collections.Generic;
Jens Geyer5a17b132019-05-26 15:53:37 +020022using System.Diagnostics;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010023using System.Text;
24using System.Threading;
25using System.Threading.Tasks;
26using Thrift.Protocol.Entities;
Jens Geyer62445c12022-06-29 00:00:00 +020027using Thrift.Protocol.Utilities;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010028using Thrift.Transport;
29
Jens Geyer4115e952023-11-21 23:00:01 +010030#pragma warning disable IDE0079 // net20 - unneeded suppression
31#pragma warning disable IDE0301 // net8 - simplified collection init
Jens Geyer0d128322021-02-25 09:42:52 +010032
Jens Geyeraa0c8b32019-01-28 23:27:45 +010033namespace Thrift.Protocol
34{
Jens Geyeraa0c8b32019-01-28 23:27:45 +010035
36 // ReSharper disable once InconsistentNaming
37 public class TCompactProtocol : TProtocol
38 {
39 private const byte ProtocolId = 0x82;
40 private const byte Version = 1;
41 private const byte VersionMask = 0x1f; // 0001 1111
42 private const byte TypeMask = 0xE0; // 1110 0000
43 private const byte TypeBits = 0x07; // 0000 0111
44 private const int TypeShiftAmount = 5;
Jens Geyer5a17b132019-05-26 15:53:37 +020045
46 private const byte NoTypeOverride = 0xFF;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010047
48 // ReSharper disable once InconsistentNaming
Jens Geyer62445c12022-06-29 00:00:00 +020049 private static readonly byte[] TTypeToCompactType = new byte[17];
50 private static readonly TType[] CompactTypeToTType = new TType[14];
Jens Geyeraa0c8b32019-01-28 23:27:45 +010051
52 /// <summary>
53 /// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
54 /// </summary>
55 private readonly Stack<short> _lastField = new Stack<short>(15);
56
57 /// <summary>
58 /// If we encounter a boolean field begin, save the TField here so it can have the value incorporated.
59 /// </summary>
60 private TField? _booleanField;
61
62 /// <summary>
63 /// If we Read a field header, and it's a boolean field, save the boolean value here so that ReadBool can use it.
64 /// </summary>
65 private bool? _boolValue;
66
67 private short _lastFieldId;
68
Jens Geyer5a17b132019-05-26 15:53:37 +020069 // minimize memory allocations by means of an preallocated bytes buffer
70 // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +010071 private readonly byte[] PreAllocatedBuffer = new byte[128];
Jens Geyer5a17b132019-05-26 15:53:37 +020072
73 private struct VarInt
74 {
75 public byte[] bytes;
76 public int count;
77 }
78
79 // minimize memory allocations by means of an preallocated VarInt buffer
80 private VarInt PreAllocatedVarInt = new VarInt()
81 {
82 bytes = new byte[10], // see Int64ToVarInt()
83 count = 0
84 };
85
86
87
88
Jens Geyeraa0c8b32019-01-28 23:27:45 +010089 public TCompactProtocol(TTransport trans)
90 : base(trans)
91 {
Jens Geyer62445c12022-06-29 00:00:00 +020092 TTypeToCompactType[(int)TType.Stop] = Types.Stop;
93 TTypeToCompactType[(int)TType.Bool] = Types.BooleanTrue;
94 TTypeToCompactType[(int)TType.Byte] = Types.Byte;
95 TTypeToCompactType[(int)TType.I16] = Types.I16;
96 TTypeToCompactType[(int)TType.I32] = Types.I32;
97 TTypeToCompactType[(int)TType.I64] = Types.I64;
98 TTypeToCompactType[(int)TType.Double] = Types.Double;
99 TTypeToCompactType[(int)TType.String] = Types.Binary;
100 TTypeToCompactType[(int)TType.List] = Types.List;
101 TTypeToCompactType[(int)TType.Set] = Types.Set;
102 TTypeToCompactType[(int)TType.Map] = Types.Map;
103 TTypeToCompactType[(int)TType.Struct] = Types.Struct;
104 TTypeToCompactType[(int)TType.Uuid] = Types.Uuid;
Jens Geyer5a17b132019-05-26 15:53:37 +0200105
106 CompactTypeToTType[Types.Stop] = TType.Stop;
107 CompactTypeToTType[Types.BooleanTrue] = TType.Bool;
108 CompactTypeToTType[Types.BooleanFalse] = TType.Bool;
109 CompactTypeToTType[Types.Byte] = TType.Byte;
110 CompactTypeToTType[Types.I16] = TType.I16;
111 CompactTypeToTType[Types.I32] = TType.I32;
112 CompactTypeToTType[Types.I64] = TType.I64;
113 CompactTypeToTType[Types.Double] = TType.Double;
114 CompactTypeToTType[Types.Binary] = TType.String;
115 CompactTypeToTType[Types.List] = TType.List;
116 CompactTypeToTType[Types.Set] = TType.Set;
117 CompactTypeToTType[Types.Map] = TType.Map;
118 CompactTypeToTType[Types.Struct] = TType.Struct;
Jens Geyer62445c12022-06-29 00:00:00 +0200119 CompactTypeToTType[Types.Uuid] = TType.Uuid;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100120 }
121
122 public void Reset()
123 {
124 _lastField.Clear();
125 _lastFieldId = 0;
126 }
127
128 public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
129 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200130 PreAllocatedBuffer[0] = ProtocolId;
131 PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask));
132 await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100133
Jens Geyer5a17b132019-05-26 15:53:37 +0200134 Int32ToVarInt((uint) message.SeqID, ref PreAllocatedVarInt);
135 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100136
137 await WriteStringAsync(message.Name, cancellationToken);
138 }
139
Jens Geyerdce22992020-05-16 23:02:27 +0200140 public override Task WriteMessageEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100141 {
Jens Geyerdce22992020-05-16 23:02:27 +0200142 cancellationToken.ThrowIfCancellationRequested();
143 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100144 }
145
146 /// <summary>
147 /// Write a struct begin. This doesn't actually put anything on the wire. We
148 /// use it as an opportunity to put special placeholder markers on the field
149 /// stack so we can get the field id deltas correct.
150 /// </summary>
Jens Geyerdce22992020-05-16 23:02:27 +0200151 public override Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100152 {
Jens Geyerdce22992020-05-16 23:02:27 +0200153 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100154
155 _lastField.Push(_lastFieldId);
156 _lastFieldId = 0;
Jens Geyerdce22992020-05-16 23:02:27 +0200157
158 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100159 }
160
Jens Geyerdce22992020-05-16 23:02:27 +0200161 public override Task WriteStructEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100162 {
Jens Geyerdce22992020-05-16 23:02:27 +0200163 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100164
165 _lastFieldId = _lastField.Pop();
Jens Geyerdce22992020-05-16 23:02:27 +0200166
167 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100168 }
169
Jens Geyer5a17b132019-05-26 15:53:37 +0200170 private async Task WriteFieldBeginInternalAsync(TField field, byte fieldType, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100171 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200172 // if there's a exType override passed in, use that. Otherwise ask GetCompactType().
173 if (fieldType == NoTypeOverride)
174 fieldType = GetCompactType(field.Type);
175
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100176
177 // check if we can use delta encoding for the field id
Jens Geyer5a17b132019-05-26 15:53:37 +0200178 if (field.ID > _lastFieldId)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100179 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200180 var delta = field.ID - _lastFieldId;
181 if (delta <= 15)
182 {
183 // Write them together
184 PreAllocatedBuffer[0] = (byte)((delta << 4) | fieldType);
185 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
186 _lastFieldId = field.ID;
187 return;
188 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100189 }
190
Jens Geyer5a17b132019-05-26 15:53:37 +0200191 // Write them separate
192 PreAllocatedBuffer[0] = fieldType;
193 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
194 await WriteI16Async(field.ID, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100195 _lastFieldId = field.ID;
196 }
197
198 public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
199 {
200 if (field.Type == TType.Bool)
201 {
202 _booleanField = field;
203 }
204 else
205 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200206 await WriteFieldBeginInternalAsync(field, NoTypeOverride, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100207 }
208 }
209
Jens Geyerdce22992020-05-16 23:02:27 +0200210 public override Task WriteFieldEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100211 {
Jens Geyerdce22992020-05-16 23:02:27 +0200212 cancellationToken.ThrowIfCancellationRequested();
213 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100214 }
215
216 public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
217 {
Jens Geyerdce22992020-05-16 23:02:27 +0200218 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100219
Jens Geyer5a17b132019-05-26 15:53:37 +0200220 PreAllocatedBuffer[0] = Types.Stop;
221 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100222 }
223
224 protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken)
225 {
Jens Geyerdce22992020-05-16 23:02:27 +0200226 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100227
228 /*
229 Abstract method for writing the start of lists and sets. List and sets on
230 the wire differ only by the exType indicator.
231 */
232
233 if (size <= 14)
234 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200235 PreAllocatedBuffer[0] = (byte)((size << 4) | GetCompactType(elemType));
236 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100237 }
238 else
239 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200240 PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(elemType));
241 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100242
Jens Geyer5a17b132019-05-26 15:53:37 +0200243 Int32ToVarInt((uint) size, ref PreAllocatedVarInt);
244 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100245 }
246 }
247
248 public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
249 {
250 await WriteCollectionBeginAsync(list.ElementType, list.Count, cancellationToken);
251 }
252
Jens Geyerdce22992020-05-16 23:02:27 +0200253 public override Task WriteListEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100254 {
Jens Geyerdce22992020-05-16 23:02:27 +0200255 cancellationToken.ThrowIfCancellationRequested();
256 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100257 }
258
259 public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
260 {
Jens Geyerdce22992020-05-16 23:02:27 +0200261 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100262
263 await WriteCollectionBeginAsync(set.ElementType, set.Count, cancellationToken);
264 }
265
Jens Geyerdce22992020-05-16 23:02:27 +0200266 public override Task WriteSetEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100267 {
Jens Geyerdce22992020-05-16 23:02:27 +0200268 cancellationToken.ThrowIfCancellationRequested();
269 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100270 }
271
272 public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
273 {
Jens Geyerdce22992020-05-16 23:02:27 +0200274 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100275
276 /*
277 Write a boolean value. Potentially, this could be a boolean field, in
278 which case the field header info isn't written yet. If so, decide what the
279 right exType header is for the value and then Write the field header.
280 Otherwise, Write a single byte.
281 */
282
283 if (_booleanField != null)
284 {
285 // we haven't written the field header yet
Jens Geyer5a17b132019-05-26 15:53:37 +0200286 var type = b ? Types.BooleanTrue : Types.BooleanFalse;
287 await WriteFieldBeginInternalAsync(_booleanField.Value, type, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100288 _booleanField = null;
289 }
290 else
291 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200292 // we're not part of a field, so just write the value.
293 PreAllocatedBuffer[0] = b ? Types.BooleanTrue : Types.BooleanFalse;
294 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100295 }
296 }
297
298 public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
299 {
Jens Geyerdce22992020-05-16 23:02:27 +0200300 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100301
Jens Geyer5a17b132019-05-26 15:53:37 +0200302 PreAllocatedBuffer[0] = (byte)b;
303 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100304 }
305
306 public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
307 {
Jens Geyerdce22992020-05-16 23:02:27 +0200308 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100309
Jens Geyer5a17b132019-05-26 15:53:37 +0200310 Int32ToVarInt(IntToZigzag(i16), ref PreAllocatedVarInt);
311 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100312 }
313
Jens Geyer5a17b132019-05-26 15:53:37 +0200314 private static void Int32ToVarInt(uint n, ref VarInt varint)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100315 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200316 // Write an i32 as a varint. Results in 1 - 5 bytes on the wire.
317 varint.count = 0;
318 Debug.Assert(varint.bytes.Length >= 5);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100319
320 while (true)
321 {
322 if ((n & ~0x7F) == 0)
323 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200324 varint.bytes[varint.count++] = (byte)n;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100325 break;
326 }
327
Jens Geyer5a17b132019-05-26 15:53:37 +0200328 varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100329 n >>= 7;
330 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100331 }
332
333 public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
334 {
Jens Geyerdce22992020-05-16 23:02:27 +0200335 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100336
Jens Geyer5a17b132019-05-26 15:53:37 +0200337 Int32ToVarInt(IntToZigzag(i32), ref PreAllocatedVarInt);
338 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100339 }
340
Jens Geyer5a17b132019-05-26 15:53:37 +0200341 static private void Int64ToVarInt(ulong n, ref VarInt varint)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100342 {
343 // Write an i64 as a varint. Results in 1-10 bytes on the wire.
Jens Geyer5a17b132019-05-26 15:53:37 +0200344 varint.count = 0;
345 Debug.Assert(varint.bytes.Length >= 10);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100346
347 while (true)
348 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200349 if ((n & ~(ulong)0x7FL) == 0)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100350 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200351 varint.bytes[varint.count++] = (byte)n;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100352 break;
353 }
Jens Geyer5a17b132019-05-26 15:53:37 +0200354 varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100355 n >>= 7;
356 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100357 }
358
359 public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
360 {
Jens Geyerdce22992020-05-16 23:02:27 +0200361 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100362
Jens Geyer5a17b132019-05-26 15:53:37 +0200363 Int64ToVarInt(LongToZigzag(i64), ref PreAllocatedVarInt);
364 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100365 }
366
367 public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
368 {
Jens Geyerdce22992020-05-16 23:02:27 +0200369 cancellationToken.ThrowIfCancellationRequested();
370
zembord9d958a32019-11-21 13:11:44 +0300371 BinaryPrimitives.WriteInt64LittleEndian(PreAllocatedBuffer, BitConverter.DoubleToInt64Bits(d));
Jens Geyer5a17b132019-05-26 15:53:37 +0200372 await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100373 }
374
375 public override async Task WriteStringAsync(string str, CancellationToken cancellationToken)
376 {
Jens Geyerdce22992020-05-16 23:02:27 +0200377 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100378
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +0100379 var buf = ArrayPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(str));
380 try
381 {
382 var numberOfBytes = Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100383
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +0100384 Int32ToVarInt((uint)numberOfBytes, ref PreAllocatedVarInt);
385 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
386 await Trans.WriteAsync(buf, 0, numberOfBytes, cancellationToken);
387 }
388 finally
389 {
390 ArrayPool<byte>.Shared.Return(buf);
391 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100392 }
393
394 public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
395 {
Jens Geyerdce22992020-05-16 23:02:27 +0200396 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100397
Jens Geyer5a17b132019-05-26 15:53:37 +0200398 Int32ToVarInt((uint) bytes.Length, ref PreAllocatedVarInt);
399 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100400 await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
401 }
402
Jens Geyer62445c12022-06-29 00:00:00 +0200403 public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
404 {
405 cancellationToken.ThrowIfCancellationRequested();
406
407 var bytes = uuid.SwapByteOrder().ToByteArray();
408 await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
409 }
410
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100411 public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
412 {
Jens Geyerdce22992020-05-16 23:02:27 +0200413 cancellationToken.ThrowIfCancellationRequested();
414
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100415 if (map.Count == 0)
416 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200417 PreAllocatedBuffer[0] = 0;
418 await Trans.WriteAsync( PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100419 }
420 else
421 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200422 Int32ToVarInt((uint) map.Count, ref PreAllocatedVarInt);
423 await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
424
425 PreAllocatedBuffer[0] = (byte)((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType));
426 await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100427 }
428 }
429
Jens Geyerdce22992020-05-16 23:02:27 +0200430 public override Task WriteMapEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100431 {
Jens Geyerdce22992020-05-16 23:02:27 +0200432 cancellationToken.ThrowIfCancellationRequested();
433 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100434 }
435
Jens Geyer5a17b132019-05-26 15:53:37 +0200436 public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100437 {
Jens Geyerdce22992020-05-16 23:02:27 +0200438 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100439
440 var protocolId = (byte) await ReadByteAsync(cancellationToken);
441 if (protocolId != ProtocolId)
442 {
443 throw new TProtocolException($"Expected protocol id {ProtocolId:X} but got {protocolId:X}");
444 }
445
446 var versionAndType = (byte) await ReadByteAsync(cancellationToken);
447 var version = (byte) (versionAndType & VersionMask);
448
449 if (version != Version)
450 {
451 throw new TProtocolException($"Expected version {Version} but got {version}");
452 }
453
454 var type = (byte) ((versionAndType >> TypeShiftAmount) & TypeBits);
455 var seqid = (int) await ReadVarInt32Async(cancellationToken);
456 var messageName = await ReadStringAsync(cancellationToken);
457
458 return new TMessage(messageName, (TMessageType) type, seqid);
459 }
460
Jens Geyerdce22992020-05-16 23:02:27 +0200461 public override Task ReadMessageEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100462 {
Jens Geyerdce22992020-05-16 23:02:27 +0200463 cancellationToken.ThrowIfCancellationRequested();
Philip Lee2d2790f2022-09-15 12:43:03 +0100464 Transport.ResetConsumedMessageSize();
Jens Geyerdce22992020-05-16 23:02:27 +0200465 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100466 }
467
Jens Geyerdce22992020-05-16 23:02:27 +0200468 public override ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100469 {
Jens Geyerdce22992020-05-16 23:02:27 +0200470 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100471
472 _lastField.Push(_lastFieldId);
473 _lastFieldId = 0;
474
Jens Geyerdce22992020-05-16 23:02:27 +0200475 return new ValueTask<TStruct>(AnonymousStruct);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100476 }
477
Jens Geyerdce22992020-05-16 23:02:27 +0200478 public override Task ReadStructEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100479 {
Jens Geyerdce22992020-05-16 23:02:27 +0200480 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100481
482 /*
483 Doesn't actually consume any wire data, just removes the last field for
484 this struct from the field stack.
485 */
486
487 // consume the last field we Read off the wire.
488 _lastFieldId = _lastField.Pop();
Jens Geyerdce22992020-05-16 23:02:27 +0200489
490 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100491 }
492
Jens Geyer5a17b132019-05-26 15:53:37 +0200493 public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100494 {
495 // Read a field header off the wire.
496 var type = (byte) await ReadByteAsync(cancellationToken);
Jens Geyer5a17b132019-05-26 15:53:37 +0200497
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100498 // if it's a stop, then we can return immediately, as the struct is over.
499 if (type == Types.Stop)
500 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200501 return StopField;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100502 }
503
Jens Geyer5a17b132019-05-26 15:53:37 +0200504
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100505 // mask off the 4 MSB of the exType header. it could contain a field id delta.
506 var modifier = (short) ((type & 0xf0) >> 4);
Jens Geyer5a17b132019-05-26 15:53:37 +0200507 var compactType = (byte)(type & 0x0f);
508
509 short fieldId;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100510 if (modifier == 0)
511 {
512 fieldId = await ReadI16Async(cancellationToken);
513 }
514 else
515 {
516 fieldId = (short) (_lastFieldId + modifier);
517 }
518
Jens Geyer5a17b132019-05-26 15:53:37 +0200519 var ttype = GetTType(compactType);
520 var field = new TField(string.Empty, ttype, fieldId);
521
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100522 // if this happens to be a boolean field, the value is encoded in the exType
Jens Geyer5a17b132019-05-26 15:53:37 +0200523 if( ttype == TType.Bool)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100524 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200525 _boolValue = (compactType == Types.BooleanTrue);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100526 }
527
528 // push the new field onto the field stack so we can keep the deltas going.
529 _lastFieldId = field.ID;
530 return field;
531 }
532
Jens Geyerdce22992020-05-16 23:02:27 +0200533 public override Task ReadFieldEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100534 {
Jens Geyerdce22992020-05-16 23:02:27 +0200535 cancellationToken.ThrowIfCancellationRequested();
536 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100537 }
538
Jens Geyer5a17b132019-05-26 15:53:37 +0200539 public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100540 {
Jens Geyerdce22992020-05-16 23:02:27 +0200541 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100542
543 /*
544 Read a map header off the wire. If the size is zero, skip Reading the key
545 and value exType. This means that 0-length maps will yield TMaps without the
546 "correct" types.
547 */
548
549 var size = (int) await ReadVarInt32Async(cancellationToken);
550 var keyAndValueType = size == 0 ? (byte) 0 : (byte) await ReadByteAsync(cancellationToken);
Jens Geyer50806452019-11-23 01:55:58 +0100551 var map = new TMap(GetTType((byte) (keyAndValueType >> 4)), GetTType((byte) (keyAndValueType & 0xf)), size);
552 CheckReadBytesAvailable(map);
553 return map;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100554 }
555
Jens Geyerdce22992020-05-16 23:02:27 +0200556 public override Task ReadMapEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100557 {
Jens Geyerdce22992020-05-16 23:02:27 +0200558 cancellationToken.ThrowIfCancellationRequested();
559 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100560 }
561
Jens Geyer5a17b132019-05-26 15:53:37 +0200562 public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100563 {
564 /*
565 Read a set header off the wire. If the set size is 0-14, the size will
566 be packed into the element exType header. If it's a longer set, the 4 MSB
567 of the element exType header will be 0xF, and a varint will follow with the
568 true size.
569 */
570
571 return new TSet(await ReadListBeginAsync(cancellationToken));
572 }
573
Jens Geyer5a17b132019-05-26 15:53:37 +0200574 public override ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100575 {
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100576 /*
577 Read a boolean off the wire. If this is a boolean field, the value should
578 already have been Read during ReadFieldBegin, so we'll just consume the
579 pre-stored value. Otherwise, Read a byte.
580 */
581
582 if (_boolValue != null)
583 {
584 var result = _boolValue.Value;
585 _boolValue = null;
Jens Geyer5a17b132019-05-26 15:53:37 +0200586 return new ValueTask<bool>(result);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100587 }
588
Jens Geyer5a17b132019-05-26 15:53:37 +0200589 return InternalCall();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100590
Jens Geyer5a17b132019-05-26 15:53:37 +0200591 async ValueTask<bool> InternalCall()
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100592 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200593 var data = await ReadByteAsync(cancellationToken);
594 return (data == Types.BooleanTrue);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100595 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100596 }
597
Jens Geyer5a17b132019-05-26 15:53:37 +0200598
599 public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
600 {
601 // Read a single byte off the wire. Nothing interesting here.
602 await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
603 return (sbyte)PreAllocatedBuffer[0];
604 }
605
606 public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100607 {
Jens Geyerdce22992020-05-16 23:02:27 +0200608 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100609
610 return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken));
611 }
612
Jens Geyer5a17b132019-05-26 15:53:37 +0200613 public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100614 {
Jens Geyerdce22992020-05-16 23:02:27 +0200615 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100616
617 return ZigzagToInt(await ReadVarInt32Async(cancellationToken));
618 }
619
Jens Geyer5a17b132019-05-26 15:53:37 +0200620 public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100621 {
Jens Geyerdce22992020-05-16 23:02:27 +0200622 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100623
624 return ZigzagToLong(await ReadVarInt64Async(cancellationToken));
625 }
626
Jens Geyer5a17b132019-05-26 15:53:37 +0200627 public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100628 {
Jens Geyerdce22992020-05-16 23:02:27 +0200629 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100630
Jens Geyer5a17b132019-05-26 15:53:37 +0200631 await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
zembord9d958a32019-11-21 13:11:44 +0300632
633 return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(PreAllocatedBuffer));
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100634 }
635
Jens Geyer5a17b132019-05-26 15:53:37 +0200636 public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100637 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200638 // read length
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100639 var length = (int) await ReadVarInt32Async(cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100640 if (length == 0)
641 {
642 return string.Empty;
643 }
644
Jens Geyer5a17b132019-05-26 15:53:37 +0200645 // read and decode data
646 if (length < PreAllocatedBuffer.Length)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100647 {
Jens Geyer5a17b132019-05-26 15:53:37 +0200648 await Trans.ReadAllAsync(PreAllocatedBuffer, 0, length, cancellationToken);
649 return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, length);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100650 }
651
Jens Geyer50806452019-11-23 01:55:58 +0100652 Transport.CheckReadBytesAvailable(length);
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +0100653
654 var buf = ArrayPool<byte>.Shared.Rent(length);
655 try
656 {
657 await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
658 return Encoding.UTF8.GetString(buf, 0, length);
659 }
660 finally
661 {
662 ArrayPool<byte>.Shared.Return(buf);
663 }
Jens Geyer5a17b132019-05-26 15:53:37 +0200664 }
665
666 public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
667 {
668 // read length
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100669 var length = (int) await ReadVarInt32Async(cancellationToken);
670 if (length == 0)
671 {
Mikel Blanchard4b66a9d2020-03-05 00:46:21 +0100672 return Array.Empty<byte>();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100673 }
674
Jens Geyer5a17b132019-05-26 15:53:37 +0200675 // read data
Jens Geyer50806452019-11-23 01:55:58 +0100676 Transport.CheckReadBytesAvailable(length);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100677 var buf = new byte[length];
678 await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
679 return buf;
680 }
681
Jens Geyer62445c12022-06-29 00:00:00 +0200682 public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
683 {
684 cancellationToken.ThrowIfCancellationRequested();
685
686 Transport.CheckReadBytesAvailable(16); // = sizeof(uuid)
687 var buf = new byte[16];
688 await Trans.ReadAllAsync(buf, 0, 16, cancellationToken);
689 return new Guid(buf).SwapByteOrder();
690 }
691
Jens Geyer5a17b132019-05-26 15:53:37 +0200692 public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100693 {
Jens Geyerdce22992020-05-16 23:02:27 +0200694 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100695
696 /*
697 Read a list header off the wire. If the list size is 0-14, the size will
698 be packed into the element exType header. If it's a longer list, the 4 MSB
699 of the element exType header will be 0xF, and a varint will follow with the
700 true size.
701 */
702
703 var sizeAndType = (byte) await ReadByteAsync(cancellationToken);
704 var size = (sizeAndType >> 4) & 0x0f;
705 if (size == 15)
706 {
707 size = (int) await ReadVarInt32Async(cancellationToken);
708 }
709
710 var type = GetTType(sizeAndType);
Jens Geyer50806452019-11-23 01:55:58 +0100711 var list = new TList(type, size);
712 CheckReadBytesAvailable(list);
713 return list;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100714 }
715
Jens Geyerdce22992020-05-16 23:02:27 +0200716 public override Task ReadListEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100717 {
Jens Geyerdce22992020-05-16 23:02:27 +0200718 cancellationToken.ThrowIfCancellationRequested();
719 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100720 }
721
Jens Geyerdce22992020-05-16 23:02:27 +0200722 public override Task ReadSetEndAsync(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100723 {
Jens Geyerdce22992020-05-16 23:02:27 +0200724 cancellationToken.ThrowIfCancellationRequested();
725 return Task.CompletedTask;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100726 }
727
728 private static byte GetCompactType(TType ttype)
729 {
730 // Given a TType value, find the appropriate TCompactProtocol.Types constant.
731 return TTypeToCompactType[(int) ttype];
732 }
733
734
Jens Geyer5a17b132019-05-26 15:53:37 +0200735 private async ValueTask<uint> ReadVarInt32Async(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100736 {
Jens Geyerdce22992020-05-16 23:02:27 +0200737 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100738
739 /*
740 Read an i32 from the wire as a varint. The MSB of each byte is set
741 if there is another byte to follow. This can Read up to 5 bytes.
742 */
743
744 uint result = 0;
745 var shift = 0;
746
747 while (true)
748 {
749 var b = (byte) await ReadByteAsync(cancellationToken);
750 result |= (uint) (b & 0x7f) << shift;
751 if ((b & 0x80) != 0x80)
752 {
753 break;
754 }
755 shift += 7;
756 }
757
758 return result;
759 }
760
Jens Geyer5a17b132019-05-26 15:53:37 +0200761 private async ValueTask<ulong> ReadVarInt64Async(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100762 {
Jens Geyerdce22992020-05-16 23:02:27 +0200763 cancellationToken.ThrowIfCancellationRequested();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100764
765 /*
766 Read an i64 from the wire as a proper varint. The MSB of each byte is set
767 if there is another byte to follow. This can Read up to 10 bytes.
768 */
769
770 var shift = 0;
771 ulong result = 0;
772 while (true)
773 {
774 var b = (byte) await ReadByteAsync(cancellationToken);
775 result |= (ulong) (b & 0x7f) << shift;
776 if ((b & 0x80) != 0x80)
777 {
778 break;
779 }
780 shift += 7;
781 }
782
783 return result;
784 }
785
786 private static int ZigzagToInt(uint n)
787 {
788 return (int) (n >> 1) ^ -(int) (n & 1);
789 }
790
791 private static long ZigzagToLong(ulong n)
792 {
793 return (long) (n >> 1) ^ -(long) (n & 1);
794 }
795
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100796 private static TType GetTType(byte type)
797 {
798 // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
Jens Geyer5a17b132019-05-26 15:53:37 +0200799 return CompactTypeToTType[type & 0x0f];
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100800 }
801
802 private static ulong LongToZigzag(long n)
803 {
804 // Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint
805 return (ulong) (n << 1) ^ (ulong) (n >> 63);
806 }
807
808 private static uint IntToZigzag(int n)
809 {
810 // Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint
811 return (uint) (n << 1) ^ (uint) (n >> 31);
812 }
813
Jens Geyer50806452019-11-23 01:55:58 +0100814 // Return the minimum number of bytes a type will consume on the wire
815 public override int GetMinSerializedSize(TType type)
816 {
817 switch (type)
818 {
Jens Geyer62445c12022-06-29 00:00:00 +0200819 case TType.Stop: return 0;
820 case TType.Void: return 0;
821 case TType.Bool: return sizeof(byte);
Jens Geyer50806452019-11-23 01:55:58 +0100822 case TType.Double: return 8; // uses fixedLongToBytes() which always writes 8 bytes
823 case TType.Byte: return sizeof(byte);
Jens Geyer62445c12022-06-29 00:00:00 +0200824 case TType.I16: return sizeof(byte); // zigzag
825 case TType.I32: return sizeof(byte); // zigzag
826 case TType.I64: return sizeof(byte); // zigzag
Jens Geyer50806452019-11-23 01:55:58 +0100827 case TType.String: return sizeof(byte); // string length
Jens Geyer62445c12022-06-29 00:00:00 +0200828 case TType.Struct: return 0; // empty struct
829 case TType.Map: return sizeof(byte); // element count
830 case TType.Set: return sizeof(byte); // element count
831 case TType.List: return sizeof(byte); // element count
832 case TType.Uuid: return 16; // uuid bytes
Jens Geyer0d128322021-02-25 09:42:52 +0100833 default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
Jens Geyer50806452019-11-23 01:55:58 +0100834 }
835 }
836
Jens Geyer421444f2019-03-20 22:13:25 +0100837 public class Factory : TProtocolFactory
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100838 {
Jens Geyer421444f2019-03-20 22:13:25 +0100839 public override TProtocol GetProtocol(TTransport trans)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100840 {
841 return new TCompactProtocol(trans);
842 }
843 }
844
845 /// <summary>
846 /// All of the on-wire exType codes.
847 /// </summary>
848 private static class Types
849 {
850 public const byte Stop = 0x00;
851 public const byte BooleanTrue = 0x01;
852 public const byte BooleanFalse = 0x02;
853 public const byte Byte = 0x03;
854 public const byte I16 = 0x04;
855 public const byte I32 = 0x05;
856 public const byte I64 = 0x06;
857 public const byte Double = 0x07;
858 public const byte Binary = 0x08;
859 public const byte List = 0x09;
860 public const byte Set = 0x0A;
861 public const byte Map = 0x0B;
862 public const byte Struct = 0x0C;
Jens Geyer62445c12022-06-29 00:00:00 +0200863 public const byte Uuid = 0x0D;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100864 }
865 }
Jens Geyer421444f2019-03-20 22:13:25 +0100866}