/// <inheritdoc /> public async Task <TTypeToDeserializeTo> DeserializeAsync <TTypeToDeserializeTo>(IBytesReadable bytesReadable, CancellationToken token) { //TODO: Implement no prefixing support if (PrefixStyle == PrefixStyle.None) { throw new NotSupportedException("Protobuf-Net deserialization without length prefixing is not yet supported."); } //To do the async read operation with Protobuf-Net we need to do some manual buffering int prefixSize = checked ((int)await ReadLongLengthPrefix(bytesReadable, PrefixStyle, token).ConfigureAwait(false)); //TODO: Reduce allocations somehow byte[] bytes = new byte[prefixSize]; int count = await bytesReadable.ReadAsync(bytes, 0, prefixSize, token) .ConfigureAwait(false); //0 means that the socket disconnected if (count == 0) { return(default(TTypeToDeserializeTo)); } return(Serializer.Deserialize <TTypeToDeserializeTo>(new MemoryStream(bytes))); }
/// <summary> /// Reads <see cref="count"/> many bytes from the reader. /// </summary> /// <param name="readable"></param> /// <param name="count">How many bytes to read.</param> /// <returns>The read bytes.</returns> public static byte[] Read(this IBytesReadable readable, int count) { if (readable == null) { throw new ArgumentNullException(nameof(readable)); } return(readable.ReadAsync(count, 0).WaitAndUnwrapException()); }
/// <summary> /// Reads asyncronously <see cref="count"/> many bytes from the reader. /// </summary> /// <param name="buffer">The buffer to store the bytes into.</param> /// <param name="start">The start position in the buffer to start reading into.</param> /// <param name="count">How many bytes to read.</param> /// <param name="timeoutInMilliseconds">How many milliseconds to wait before canceling the operation.</param> /// <returns>A future for the read bytes.</returns> public static Task <int> ReadAsync(this IBytesReadable readable, byte[] buffer, int start, int count, int timeoutInMilliseconds) { if (readable == null) { throw new ArgumentNullException(nameof(readable)); } //TODO: DO we need to check the timeout? return(readable.ReadAsync(buffer, 0, count, timeoutInMilliseconds > 0 ? new CancellationTokenSource(timeoutInMilliseconds).Token : CancellationToken.None)); }
/// <summary> /// Reads asyncronously <see cref="count"/> many bytes from the reader. /// </summary> /// <param name="readable"></param> /// <param name="count">How many bytes to read.</param> /// <param name="timeoutInMilliseconds">How many milliseconds to wait before canceling the operation.</param> /// <returns>A future for the read bytes.</returns> public static async Task <byte[]> ReadAsync(this IBytesReadable readable, int count, int timeoutInMilliseconds) { if (readable == null) { throw new ArgumentNullException(nameof(readable)); } byte[] bytes = new byte[count]; int resultCount = await readable.ReadAsync(bytes, 0, count, timeoutInMilliseconds) .ConfigureAwait(false); if (resultCount != count) { throw new InvalidOperationException($"Failed to read {count} many bytes form {nameof(IBytesReadable)}. Read {resultCount} many bytes."); } return(bytes); }
//TODO: Doc /// <summary> /// Asyncly reads a byte chunk from the <see cref="bytesReadable"/> /// or throws if unable. /// </summary> /// <param name="bytesReadable"></param> /// <param name="style"></param> /// <param name="token"></param> /// <returns></returns> private static async Task <byte[]> ReadFixed4Byte(IBytesReadable bytesReadable, PrefixStyle style, CancellationToken token) { byte[] bytes = new byte[4]; int count = await bytesReadable.ReadAsync(bytes, 0, 4, token) .ConfigureAwait(false); //0 means the socket disconnected if (count == 0) { return(null); } if (count < 4) { throw new InvalidOperationException($"Protobuf-Net could not read length prefix: {style}"); } return(bytes); }
/// <returns>The number of bytes consumed; 0 if no data available</returns> private static async Task <ulong> TryReadUInt64Variant(IBytesReadable bytesReadable, CancellationToken token) { //TODO: Reuse-share buffer to reduce allocations byte[] tempBuffer = new byte[9]; ulong value = 0; int count = await bytesReadable.ReadAsync(tempBuffer, 0, 1, token) .ConfigureAwait(false); //0 means that the socket disconnected if (count == 0) { return(0); } int b = tempBuffer[0]; if (b < 0) { return(0); } value = (uint)b; if ((value & 0x80) == 0) { return(1); } value &= 0x7F; int bytesRead = 1, shift = 7; while (bytesRead < 9) { count = await bytesReadable.ReadAsync(tempBuffer, bytesRead, 1, token) .ConfigureAwait(false); //0 means the underlying socket disconnected if (count == 0) { return(0); } b = tempBuffer[bytesRead]; if (b < 0) { throw EoF(null); } value |= ((ulong)b & 0x7F) << shift; shift += 7; if ((b & 0x80) == 0) { return(value); } bytesRead++; } count = await bytesReadable.ReadAsync(tempBuffer, bytesRead, 1, token) .ConfigureAwait(false); if (count == 0) { return(0); } b = tempBuffer[bytesRead]; if (b < 0) { throw EoF(null); } if ((b & 1) == 0) // only use 1 bit from the last byte { value |= ((ulong)b & 0x7F) << shift; } return(value); }