From fbd478e69fdd3b3ba1e016e008c4478216769194 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 25 Nov 2024 13:27:12 -0700 Subject: [PATCH 01/20] Experimental API for more efficient async deserialization --- src/Nerdbank.MessagePack/MessagePackReader.cs | 138 ++++------ .../MessagePackStreamingReader.cs | 256 ++++++++++++++++++ .../MessagePackStreamingReaderTests.cs | 82 ++++++ 3 files changed, 387 insertions(+), 89 deletions(-) create mode 100644 src/Nerdbank.MessagePack/MessagePackStreamingReader.cs create mode 100644 test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 34925b3d..171ecfd4 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -21,7 +21,7 @@ public ref partial struct MessagePackReader /// /// The reader over the sequence. /// - private SequenceReader reader; + private MessagePackStreamingReader streamingReader; /// public MessagePackReader(ReadOnlyMemory msgpack) @@ -36,9 +36,12 @@ public MessagePackReader(ReadOnlyMemory msgpack) public MessagePackReader(scoped in ReadOnlySequence msgpack) : this() { - this.reader = new SequenceReader(msgpack); + this.streamingReader = new(msgpack, null, null); } + [UnscopedRef] + private ref SequenceReader reader => ref this.streamingReader.SequenceReader; + /// /// Gets the originally supplied to the constructor. /// @@ -120,11 +123,14 @@ public byte NextCode /// public void ReadNil() { - ThrowInsufficientBufferUnless(this.reader.TryRead(out byte code)); - - if (code != MessagePackCode.Nil) + switch (this.streamingReader.TryReadNil()) { - throw ThrowInvalidCode(code); + case MessagePackPrimitives.DecodeResult.Success: + return; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + default: + throw ThrowNotEnoughBytesException(); } } @@ -136,13 +142,16 @@ public void ReadNil() [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryReadNil() { - if (this.NextCode == MessagePackCode.Nil) + switch (this.streamingReader.TryReadNil()) { - this.reader.Advance(1); - return true; + case MessagePackPrimitives.DecodeResult.Success: + return true; + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + throw ThrowNotEnoughBytesException(); + default: + return false; } - - return false; } /// @@ -222,44 +231,19 @@ public int ReadArrayHeader() [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryReadArrayHeader(out int count) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadArrayHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); - count = checked((int)uintCount); - if (readResult == MessagePackPrimitives.DecodeResult.Success) + switch (this.streamingReader.TryReadArrayHeader(out count)) { - this.reader.Advance(tokenSize); - return true; + case MessagePackPrimitives.DecodeResult.Success: + return true; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + return false; + default: + throw ThrowUnreachable(); } - return SlowPath(ref this, readResult, ref count, ref tokenSize); - - static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, ref int count, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return true; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryReadArrayHeader(buffer, out uint uintCount, out tokenSize); - count = checked((int)uintCount); - return SlowPath(ref self, readResult, ref count, ref tokenSize); - } - else - { - count = 0; - return false; - } - - default: - throw ThrowUnreachable(); - } - } } /// @@ -298,43 +282,17 @@ public int ReadMapHeader() /// Thrown if a code other than an map header is encountered. public bool TryReadMapHeader(out int count) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadMapHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); - count = checked((int)uintCount); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return true; - } - - return SlowPath(ref this, readResult, ref count, ref tokenSize); - - static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, ref int count, ref int tokenSize) + switch (this.streamingReader.TryReadMapHeader(out count)) { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return true; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryReadMapHeader(buffer, out uint uintCount, out tokenSize); - count = checked((int)uintCount); - return SlowPath(ref self, readResult, ref count, ref tokenSize); - } - else - { - count = 0; - return false; - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return true; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + return false; + default: + throw ThrowUnreachable(); } } @@ -344,15 +302,17 @@ static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRes /// The value. public bool ReadBoolean() { - ThrowInsufficientBufferUnless(this.reader.TryRead(out byte code)); - switch (code) + switch (this.streamingReader.TryReadBoolean(out bool value)) { - case MessagePackCode.True: - return true; - case MessagePackCode.False: - return false; + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); default: - throw ThrowInvalidCode(code); + throw ThrowUnreachable(); } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs new file mode 100644 index 00000000..9f2c7fca --- /dev/null +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -0,0 +1,256 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics.CodeAnalysis; +using System.IO.Pipelines; +using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; + +namespace Nerdbank.MessagePack; + +public ref struct MessagePackStreamingReader +{ + private readonly GetMoreBytesAsync? getMoreBytesAsync; + private readonly object? getMoreBytesState; + private SequenceReader reader; + + /// + /// A value indicating whether no more bytes can be expected once we reach the end of the current buffer. + /// + private bool eof; + + public MessagePackStreamingReader(scoped in ReadOnlySequence sequence) + : this(sequence, null, null) + { + } + + public MessagePackStreamingReader(scoped in ReadOnlySequence sequence, GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) + { + this.reader = new SequenceReader(sequence); + this.getMoreBytesAsync = additionalBytesSource; + this.getMoreBytesState = getMoreBytesState; + ; + } + + public MessagePackStreamingReader(scoped in BufferRefresh refresh) + : this(refresh.Buffer, refresh.GetMoreBytes, refresh.GetMoreBytesState) + { + this.CancellationToken = refresh.CancellationToken; + this.eof = refresh.EndOfStream; + } + + /// + /// A delegate that can be used to get more bytes to complete the operation. + /// + /// A state object. + /// + /// The position after the last consumed byte (i.e. the last byte from the original buffer that is not expected to be included to the new buffer). + /// Any bytes at or following this position that were in the original buffer must be included to the buffer returned from this method. + /// + /// A cancellation token. + /// The available buffer, which must contain more bytes than remained after if there are any more bytes to be had. + public delegate ValueTask GetMoreBytesAsync(object? state, SequencePosition consumed, CancellationToken cancellationToken); + + public CancellationToken CancellationToken { get; init; } + + [UnscopedRef] + internal ref SequenceReader SequenceReader => ref this.reader; + + private DecodeResult InsufficientBytes => this.eof ? DecodeResult.EmptyBuffer : DecodeResult.InsufficientBuffer; + + public DecodeResult TryReadNil() + { + if (this.reader.TryPeek(out byte next)) + { + if (next == MessagePackCode.Nil) + { + this.reader.Advance(1); + return DecodeResult.Success; + } + + return DecodeResult.TokenMismatch; + } + else + { + return this.InsufficientBytes; + } + } + + public DecodeResult TryReadBoolean(out bool value) + { + if (this.reader.TryPeek(out byte next)) + { + switch (next) + { + case MessagePackCode.True: + value = true; + break; + case MessagePackCode.False: + value = false; + break; + default: + value = false; + return DecodeResult.TokenMismatch; + } + + this.reader.Advance(1); + return DecodeResult.Success; + } + else + { + value = false; + return this.InsufficientBytes; + } + } + + public DecodeResult TryReadArrayHeader(out int count) + { + DecodeResult readResult = MessagePackPrimitives.TryReadArrayHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); + count = checked((int)uintCount); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref count, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref int count, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryReadArrayHeader(buffer, out uint uintCount, out tokenSize); + count = checked((int)uintCount); + return SlowPath(ref self, readResult, ref count, ref tokenSize); + } + else + { + count = 0; + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + public DecodeResult TryReadMapHeader(out int count) + { + DecodeResult readResult = MessagePackPrimitives.TryReadMapHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); + count = checked((int)uintCount); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref count, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref int count, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryReadMapHeader(buffer, out uint uintCount, out tokenSize); + count = checked((int)uintCount); + return SlowPath(ref self, readResult, ref count, ref tokenSize); + } + else + { + count = 0; + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Gets the information to return from an async method that has been using this reader + /// so that the caller knows how to resume reading. + /// + /// The value to pass to . + public readonly BufferRefresh GetExchangeInfo() => new() + { + CancellationToken = this.CancellationToken, + Buffer = this.reader.UnreadSequence, + GetMoreBytes = this.getMoreBytesAsync, + GetMoreBytesState = this.getMoreBytesState, + EndOfStream = this.eof, + }; + + /// + /// Adds more bytes to the buffer being decoded, if they are available. + /// + /// The value to pass to . + /// Thrown if no more bytes are available. + /// + /// This is a destructive operation to this value. + /// It must not be used after calling this method. + /// Instead, the result can use the result of this method to recreate a new value. + /// + public ValueTask ReplenishBufferAsync() + { + if (this.getMoreBytesAsync is null || this.eof) + { + throw new EndOfStreamException($"Additional bytes are required to complete the operation and no means to get more was provided."); + } + + this.CancellationToken.ThrowIfCancellationRequested(); + ValueTask result = Helper(this.getMoreBytesAsync, this.getMoreBytesState, this.reader.Position, this.reader.Sequence.End, this.CancellationToken); + + // Having made the call to request more bytes, our caller can no longer use this struct because the buffers it had are assumed to have been recycled. + this.reader = default; + return result; + + static async ValueTask Helper(GetMoreBytesAsync getMoreBytes, object? getMoreBytesState, SequencePosition consumed, SequencePosition examined, CancellationToken cancellationToken) + { + ReadResult moreBuffer = await getMoreBytes(getMoreBytesState, consumed, cancellationToken); + return new BufferRefresh + { + CancellationToken = cancellationToken, + Buffer = moreBuffer.Buffer, + GetMoreBytes = getMoreBytes, + GetMoreBytesState = getMoreBytesState, + EndOfStream = moreBuffer.IsCompleted, + }; + } + } + + [DoesNotReturn] + private static DecodeResult ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + + public struct BufferRefresh + { + internal CancellationToken CancellationToken { get; init; } + + internal ReadOnlySequence Buffer { get; init; } + + internal GetMoreBytesAsync? GetMoreBytes { get; init; } + + internal object? GetMoreBytesState { get; init; } + + internal bool EndOfStream { get; init; } + } +} diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs new file mode 100644 index 00000000..1694afa7 --- /dev/null +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -0,0 +1,82 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; + +public class MessagePackStreamingReaderTests +{ + private static readonly ReadOnlySequence ArrayOf3Bools = CreateMsgPackArrayOf3Bools(); + + [Fact] + public void ReadIncompleteBuffer() + { + MessagePackStreamingReader incompleteReader = new(ArrayOf3Bools.Slice(0, 2)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); + Assert.Equal(3, count); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.False(boolean); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + } + + [Fact] + public async Task ReplenishBufferAsync_AddsMoreBytesOnce() + { + // Arrange the reader to have an incomplete buffer and that upon request it will get the rest of it. + MessagePackStreamingReader incompleteReader = new( + ArrayOf3Bools.Slice(0, 2), + (_, pos, ct) => new(new ReadResult(ArrayOf3Bools.Slice(pos), false, isCompleted: true)), + null); + + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); + Assert.Equal(3, count); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.False(boolean); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.True(boolean); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.False(boolean); + + Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); + } + + [Fact] + public async Task ReplenishBufferAsync_AddsMoreBytes_ThenCompletes() + { + // Arrange the reader to have an incomplete buffer and that upon request it will get the rest of it. + int callCount = 0; + MessagePackStreamingReader incompleteReader = new( + ArrayOf3Bools.Slice(0, 2), + (_, pos, ct) => new(new ReadResult(ArrayOf3Bools.Slice(pos), false, isCompleted: ++callCount > 1)), + null); + + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); + Assert.Equal(3, count); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.False(boolean); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.True(boolean); + Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.False(boolean); + + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadNil()); + incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); + } + + private static ReadOnlySequence CreateMsgPackArrayOf3Bools() + { + Sequence seq = new(); + MessagePackWriter writer = new(seq); + writer.WriteArrayHeader(3); + writer.Write(false); + writer.Write(true); + writer.Write(false); + writer.Flush(); + + return seq; + } +} From fe64295fec4a1fb9a2dd3c6ea7e2029bd746d76a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Nov 2024 23:08:54 -0700 Subject: [PATCH 02/20] More conversion --- src/Nerdbank.MessagePack/MessagePackReader.cs | 60 ++++++------------- .../MessagePackStreamingReader.cs | 53 ++++++++++++++++ 2 files changed, 71 insertions(+), 42 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 171ecfd4..acbd7916 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -164,15 +164,15 @@ public bool TryReadNil() /// public ReadOnlySequence ReadRaw(long length) { - try + switch (this.streamingReader.TryReadRaw(length, out ReadOnlySequence result)) { - ReadOnlySequence result = this.reader.Sequence.Slice(this.reader.Position, length); - this.reader.Advance(length); - return result; - } - catch (ArgumentOutOfRangeException ex) - { - throw ThrowNotEnoughBytesException(ex); + case MessagePackPrimitives.DecodeResult.Success: + return result; + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -704,41 +704,17 @@ public ExtensionHeader ReadExtensionHeader() /// public bool TryReadExtensionHeader(out ExtensionHeader extensionHeader) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadExtensionHeader(this.reader.UnreadSpan, out extensionHeader, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) + switch (this.streamingReader.TryReadExtensionHeader(out extensionHeader)) { - this.reader.Advance(tokenSize); - return true; - } - - return SlowPath(ref this, readResult, ref extensionHeader, ref tokenSize); - - static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, ref ExtensionHeader extensionHeader, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return true; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryReadExtensionHeader(buffer, out extensionHeader, out tokenSize); - return SlowPath(ref self, readResult, ref extensionHeader, ref tokenSize); - } - else - { - extensionHeader = default; - return false; - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return true; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 9f2c7fca..c581b576 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -186,6 +186,59 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + public DecodeResult TryReadRaw(long length, out ReadOnlySequence rawMsgPack) + { + if (this.reader.Remaining >= length) + { + rawMsgPack = this.reader.Sequence.Slice(this.reader.Position, length); + this.reader.Advance(length); + return DecodeResult.Success; + } + + rawMsgPack = default; + return this.InsufficientBytes; + } + + public DecodeResult TryReadExtensionHeader(out ExtensionHeader extensionHeader) + { + DecodeResult readResult = MessagePackPrimitives.TryReadExtensionHeader(this.reader.UnreadSpan, out extensionHeader, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref extensionHeader, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref ExtensionHeader extensionHeader, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryReadExtensionHeader(buffer, out extensionHeader, out tokenSize); + return SlowPath(ref self, readResult, ref extensionHeader, ref tokenSize); + } + else + { + extensionHeader = default; + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + /// /// Gets the information to return from an async method that has been using this reader /// so that the caller knows how to resume reading. From 519db3b19d8d035dbcba86e2dea32f5e86e70074 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Nov 2024 08:23:17 -0700 Subject: [PATCH 03/20] Migrate more to the streaming reader --- .../MessagePackReader.Integers.cs | 360 ++++------------ .../MessagePackReader.Integers.tt | 43 +- src/Nerdbank.MessagePack/MessagePackReader.cs | 8 +- .../MessagePackStreamingReader.Integers.cs | 393 ++++++++++++++++++ .../MessagePackStreamingReader.Integers.tt | 86 ++++ .../MessagePackStreamingReader.cs | 2 +- .../Nerdbank.MessagePack.csproj | 9 + 7 files changed, 589 insertions(+), 312 deletions(-) create mode 100644 src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs create mode 100644 src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt diff --git a/src/Nerdbank.MessagePack/MessagePackReader.Integers.cs b/src/Nerdbank.MessagePack/MessagePackReader.Integers.cs index 9da82b67..b81cf22e 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.Integers.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.Integers.cs @@ -23,40 +23,17 @@ public ref partial struct MessagePackReader /// Thrown when the value exceeds what can be stored in the returned type. public Byte ReadByte() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out Byte value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static Byte SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, Byte value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out Byte value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -70,40 +47,17 @@ static Byte SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRes /// Thrown when the value exceeds what can be stored in the returned type. public UInt16 ReadUInt16() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out UInt16 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static UInt16 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, UInt16 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out UInt16 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -117,40 +71,17 @@ static UInt16 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeR /// Thrown when the value exceeds what can be stored in the returned type. public UInt32 ReadUInt32() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out UInt32 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static UInt32 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, UInt32 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out UInt32 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -164,40 +95,17 @@ static UInt32 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeR /// Thrown when the value exceeds what can be stored in the returned type. public UInt64 ReadUInt64() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out UInt64 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static UInt64 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, UInt64 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out UInt64 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -211,40 +119,17 @@ static UInt64 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeR /// Thrown when the value exceeds what can be stored in the returned type. public SByte ReadSByte() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out SByte value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static SByte SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, SByte value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out SByte value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -258,40 +143,17 @@ static SByte SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRe /// Thrown when the value exceeds what can be stored in the returned type. public Int16 ReadInt16() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out Int16 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static Int16 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, Int16 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out Int16 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -305,40 +167,17 @@ static Int16 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRe /// Thrown when the value exceeds what can be stored in the returned type. public Int32 ReadInt32() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out Int32 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static Int32 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, Int32 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out Int32 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -352,40 +191,17 @@ static Int32 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRe /// Thrown when the value exceeds what can be stored in the returned type. public Int64 ReadInt64() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out Int64 value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static Int64 SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, Int64 value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + switch (this.streamingReader.TryRead(out Int64 value)) + { + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } } diff --git a/src/Nerdbank.MessagePack/MessagePackReader.Integers.tt b/src/Nerdbank.MessagePack/MessagePackReader.Integers.tt index 96183cc7..fcfe7b6d 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.Integers.tt +++ b/src/Nerdbank.MessagePack/MessagePackReader.Integers.tt @@ -44,40 +44,17 @@ foreach (var intType in allTypes) { /// Thrown when the value exceeds what can be stored in the returned type. public <#=intType.Name#> Read<#=intType.Name#>() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out <#= intType.Name #> value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) + switch (this.streamingReader.TryRead(out <#=intType.Name#> value)) { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static <#= intType.Name #> SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, <#= intType.Name #> value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } <# } #> diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index acbd7916..721976a2 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -696,12 +696,8 @@ public ExtensionHeader ReadExtensionHeader() /// if there is sufficient buffer to read it. /// /// Receives the extension header if the remaining bytes in the fully describe the header. - /// The number of key=value pairs in the map. + /// A value indicating whether an extension header is fully represented at the reader's position. /// Thrown if a code other than an extension format header is encountered. - /// - /// When this method returns the position of the reader is left in an undefined position. - /// The caller is expected to recreate the reader (presumably with a longer sequence to read from) before continuing. - /// public bool TryReadExtensionHeader(out ExtensionHeader extensionHeader) { switch (this.streamingReader.TryReadExtensionHeader(out extensionHeader)) @@ -712,7 +708,7 @@ public bool TryReadExtensionHeader(out ExtensionHeader extensionHeader) throw ThrowInvalidCode(this.NextCode); case MessagePackPrimitives.DecodeResult.EmptyBuffer: case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - throw ThrowNotEnoughBytesException(); + return false; default: throw ThrowUnreachable(); } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs new file mode 100644 index 00000000..fbec9ccf --- /dev/null +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs @@ -0,0 +1,393 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// This file was originally derived from https://github.com/MessagePack-CSharp/MessagePack-CSharp/ + +/* THIS (.cs) FILE IS GENERATED. DO NOT CHANGE IT. + * CHANGE THE .tt FILE INSTEAD. */ + +#pragma warning disable SA1121 // Simplify type syntax +#pragma warning disable SA1601 // Partial elements should be documented + +using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; + +namespace Nerdbank.MessagePack; + +public ref partial struct MessagePackStreamingReader +{ + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out Byte value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref Byte value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out UInt16 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref UInt16 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out UInt32 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref UInt32 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out UInt64 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref UInt64 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out SByte value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref SByte value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out Int16 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref Int16 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out Int32 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref Int32 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out Int64 value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref Int64 value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } +} diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt new file mode 100644 index 00000000..c270a8b4 --- /dev/null +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt @@ -0,0 +1,86 @@ +<#@ assembly name="System.Core" #> +<#@ Import Namespace="System.Linq" #> +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// This file was originally derived from https://github.com/MessagePack-CSharp/MessagePack-CSharp/ + +/* THIS (.cs) FILE IS GENERATED. DO NOT CHANGE IT. + * CHANGE THE .tt FILE INSTEAD. */ + +#pragma warning disable SA1121 // Simplify type syntax +#pragma warning disable SA1601 // Partial elements should be documented + +using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; + +namespace Nerdbank.MessagePack; + +public ref partial struct MessagePackStreamingReader +{<# +var unsignedTypes = new Type[] +{ + typeof(byte), + typeof(ushort), + typeof(uint), + typeof(ulong), +}; +var signedTypes = new Type[] +{ + typeof(sbyte), + typeof(short), + typeof(int), + typeof(long), +}; + +var allTypes = unsignedTypes.Concat(signedTypes); +foreach (var intType in allTypes) { +#> + + /// + /// Reads an value from: + /// Some value between and , + /// Some value between and , + /// or any of the other MsgPack integer types. + /// + /// The value. + /// Thrown when the value exceeds what can be stored in the returned type. + public DecodeResult TryRead(out <#=intType.Name#> value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref <#= intType.Name #> value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } +<# } #> +} diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index c581b576..3e238fef 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -7,7 +7,7 @@ namespace Nerdbank.MessagePack; -public ref struct MessagePackStreamingReader +public ref partial struct MessagePackStreamingReader { private readonly GetMoreBytesAsync? getMoreBytesAsync; private readonly object? getMoreBytesState; diff --git a/src/Nerdbank.MessagePack/Nerdbank.MessagePack.csproj b/src/Nerdbank.MessagePack/Nerdbank.MessagePack.csproj index 75434c33..46ecc365 100644 --- a/src/Nerdbank.MessagePack/Nerdbank.MessagePack.csproj +++ b/src/Nerdbank.MessagePack/Nerdbank.MessagePack.csproj @@ -34,6 +34,10 @@ TextTemplatingFileGenerator MessagePackSerializer.AutomatedFriendlyOverloads.cs + + TextTemplatingFileGenerator + MessagePackStreamingReader.Integers.cs + @@ -75,6 +79,11 @@ True MessagePackSerializer.AutomatedFriendlyOverloads.tt + + True + True + MessagePackStreamingReader.Integers.tt + From e91b6cb948868723bfb79b5fde5f643f89242013 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Nov 2024 20:59:35 -0700 Subject: [PATCH 04/20] Move more --- src/Nerdbank.MessagePack/MessagePackReader.cs | 86 ++++--------------- .../MessagePackStreamingReader.cs | 80 ++++++++++++++++- .../MessagePackStreamingReaderTests.cs | 20 ++--- 3 files changed, 108 insertions(+), 78 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 721976a2..f725051d 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -302,7 +302,7 @@ public bool TryReadMapHeader(out int count) /// The value. public bool ReadBoolean() { - switch (this.streamingReader.TryReadBoolean(out bool value)) + switch (this.streamingReader.TryRead(out bool value)) { case MessagePackPrimitives.DecodeResult.Success: return value; @@ -342,40 +342,16 @@ public bool ReadBoolean() /// The value. public unsafe float ReadSingle() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out float value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static float SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, float value, ref int tokenSize) + switch (this.streamingReader.TryRead(out float value)) { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -397,40 +373,16 @@ static float SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeRe /// The value. public unsafe double ReadDouble() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out double value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static double SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, double value, ref int tokenSize) + switch (this.streamingReader.TryRead(out double value)) { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 3e238fef..33efa2e0 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -75,7 +75,7 @@ public DecodeResult TryReadNil() } } - public DecodeResult TryReadBoolean(out bool value) + public DecodeResult TryRead(out bool value) { if (this.reader.TryPeek(out byte next)) { @@ -102,6 +102,84 @@ public DecodeResult TryReadBoolean(out bool value) } } + public DecodeResult TryRead(out float value) + { + MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == MessagePackPrimitives.DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPrimitives.DecodeResult readResult, ref float value, ref int tokenSize) + { + switch (readResult) + { + case MessagePackPrimitives.DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + public DecodeResult TryRead(out double value) + { + MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == MessagePackPrimitives.DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPrimitives.DecodeResult readResult, ref double value, ref int tokenSize) + { + switch (readResult) + { + case MessagePackPrimitives.DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + public DecodeResult TryReadArrayHeader(out int count) { DecodeResult readResult = MessagePackPrimitives.TryReadArrayHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index 1694afa7..9e15f87d 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -13,9 +13,9 @@ public void ReadIncompleteBuffer() MessagePackStreamingReader incompleteReader = new(ArrayOf3Bools.Slice(0, 2)); Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); Assert.Equal(3, count); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); - Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); } [Fact] @@ -29,13 +29,13 @@ public async Task ReplenishBufferAsync_AddsMoreBytesOnce() Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); Assert.Equal(3, count); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); - Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); @@ -53,13 +53,13 @@ public async Task ReplenishBufferAsync_AddsMoreBytes_ThenCompletes() Assert.Equal(DecodeResult.Success, incompleteReader.TryReadArrayHeader(out int count)); Assert.Equal(3, count); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out bool boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); - Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); - Assert.Equal(DecodeResult.Success, incompleteReader.TryReadBoolean(out boolean)); + Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadNil()); From 53dd2dfc9a814a9ebd3e04779d7ada112dcf3bd9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Nov 2024 21:16:09 -0700 Subject: [PATCH 05/20] Move ReadDateTime --- src/Nerdbank.MessagePack/MessagePackReader.cs | 86 +++++-------------- .../MessagePackStreamingReader.cs | 86 ++++++++++++++++++- 2 files changed, 102 insertions(+), 70 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index f725051d..56437102 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -396,40 +396,17 @@ public unsafe double ReadDouble() /// The value. public DateTime ReadDateTime() { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out DateTime value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) + switch (this.streamingReader.TryRead(out DateTime value)) { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, readResult, value, ref tokenSize); - - static DateTime SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, DateTime value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); - return SlowPath(ref self, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -444,40 +421,17 @@ static DateTime SlowPath(ref MessagePackReader self, MessagePackPrimitives.Decod /// The value. public DateTime ReadDateTime(ExtensionHeader header) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, header, out DateTime value, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) + switch (this.streamingReader.TryRead(header, out DateTime value)) { - this.reader.Advance(tokenSize); - return value; - } - - return SlowPath(ref this, header, readResult, value, ref tokenSize); - - static DateTime SlowPath(ref MessagePackReader self, ExtensionHeader header, MessagePackPrimitives.DecodeResult readResult, DateTime value, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return value; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryRead(buffer, header, out value, out tokenSize); - return SlowPath(ref self, header, readResult, value, ref tokenSize); - } - else - { - throw ThrowNotEnoughBytesException(); - } - - default: - throw ThrowUnreachable(); - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 33efa2e0..092e0973 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -104,7 +104,7 @@ public DecodeResult TryRead(out bool value) public DecodeResult TryRead(out float value) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); if (readResult == MessagePackPrimitives.DecodeResult.Success) { this.reader.Advance(tokenSize); @@ -113,7 +113,7 @@ public DecodeResult TryRead(out float value) return SlowPath(ref this, readResult, ref value, ref tokenSize); - static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPrimitives.DecodeResult readResult, ref float value, ref int tokenSize) + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref float value, ref int tokenSize) { switch (readResult) { @@ -143,7 +143,7 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPri public DecodeResult TryRead(out double value) { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); if (readResult == MessagePackPrimitives.DecodeResult.Success) { this.reader.Advance(tokenSize); @@ -152,7 +152,7 @@ public DecodeResult TryRead(out double value) return SlowPath(ref this, readResult, ref value, ref tokenSize); - static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPrimitives.DecodeResult readResult, ref double value, ref int tokenSize) + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref double value, ref int tokenSize) { switch (readResult) { @@ -180,6 +180,84 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPri } } + public DecodeResult TryRead(out DateTime value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref DateTime value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, out value, out tokenSize); + return SlowPath(ref self, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + + public DecodeResult TryRead(ExtensionHeader extensionHeader, out DateTime value) + { + DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, extensionHeader, out value, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, extensionHeader, readResult, ref value, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, ExtensionHeader header, DecodeResult readResult, ref DateTime value, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryRead(buffer, header, out value, out tokenSize); + return SlowPath(ref self, header, readResult, ref value, ref tokenSize); + } + else + { + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + public DecodeResult TryReadArrayHeader(out int count) { DecodeResult readResult = MessagePackPrimitives.TryReadArrayHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); From 5e7a7fa7f4af9cf48e62bcc1f9787b51c9c457bb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Nov 2024 21:51:27 -0700 Subject: [PATCH 06/20] Move string reads --- src/Nerdbank.MessagePack/MessagePackReader.cs | 103 ++++--------- .../MessagePackStreamingReader.cs | 144 ++++++++++++++++++ 2 files changed, 170 insertions(+), 77 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 56437102..88a5ab85 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -506,27 +506,24 @@ public DateTime ReadDateTime(ExtensionHeader header) /// public bool TryReadStringSpan(out ReadOnlySpan span) { - if (this.IsNil) + switch (this.streamingReader.TryReadStringSpan(out bool contiguous, out span)) { - span = default; - return false; - } - - long oldPosition = this.reader.Consumed; - int length = checked((int)this.GetStringLengthInBytes()); - ThrowInsufficientBufferUnless(this.reader.Remaining >= length); + case MessagePackPrimitives.DecodeResult.Success: + return contiguous; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + if (this.streamingReader.TryPeekNextCode(out byte code) == MessagePackPrimitives.DecodeResult.Success + && code == MessagePackCode.Nil) + { + span = default; + return false; + } - if (this.reader.CurrentSpanIndex + length <= this.reader.CurrentSpan.Length) - { - span = this.reader.CurrentSpan.Slice(this.reader.CurrentSpanIndex, length); - this.reader.Advance(length); - return true; - } - else - { - this.reader.Rewind(this.reader.Consumed - oldPosition); - span = default; - return false; + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -541,24 +538,17 @@ public bool TryReadStringSpan(out ReadOnlySpan span) [MethodImpl(MethodImplOptions.AggressiveInlining)] public string? ReadString() { - if (this.TryReadNil()) - { - return null; - } - - uint byteLength = this.GetStringLengthInBytes(); - - ReadOnlySpan unreadSpan = this.reader.UnreadSpan; - if (unreadSpan.Length >= byteLength) - { - // Fast path: all bytes to decode appear in the same span. - string value = StringEncoding.UTF8.GetString(unreadSpan.Slice(0, checked((int)byteLength))); - this.reader.Advance(byteLength); - return value; - } - else + switch (this.streamingReader.TryRead(out string? value)) { - return this.ReadStringSlow(byteLength); + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } @@ -878,47 +868,6 @@ private uint GetStringLengthInBytes() return length; } - /// - /// Reads a string assuming that it is spread across multiple spans in the . - /// - /// The length of the string to be decoded, in bytes. - /// The decoded string. - private string ReadStringSlow(uint byteLength) - { - ThrowInsufficientBufferUnless(this.reader.Remaining >= byteLength); - - // We need to decode bytes incrementally across multiple spans. - int remainingByteLength = checked((int)byteLength); - int maxCharLength = StringEncoding.UTF8.GetMaxCharCount(remainingByteLength); - char[] charArray = ArrayPool.Shared.Rent(maxCharLength); - System.Text.Decoder decoder = StringEncoding.UTF8.GetDecoder(); - - int initializedChars = 0; - while (remainingByteLength > 0) - { - int bytesRead = Math.Min(remainingByteLength, this.reader.UnreadSpan.Length); - remainingByteLength -= bytesRead; - bool flush = remainingByteLength == 0; -#if NETCOREAPP - initializedChars += decoder.GetChars(this.reader.UnreadSpan.Slice(0, bytesRead), charArray.AsSpan(initializedChars), flush); -#else - unsafe - { - fixed (byte* pUnreadSpan = this.reader.UnreadSpan) - fixed (char* pCharArray = &charArray[initializedChars]) - { - initializedChars += decoder.GetChars(pUnreadSpan, bytesRead, pCharArray, charArray.Length - initializedChars, flush); - } - } -#endif - this.reader.Advance(bytesRead); - } - - string value = new string(charArray, 0, initializedChars); - ArrayPool.Shared.Return(charArray); - return value; - } - private bool TrySkipNextArray(SerializationContext context) => this.TryReadArrayHeader(out int count) && this.TrySkip(count, context); private bool TrySkipNextMap(SerializationContext context) => this.TryReadMapHeader(out int count) && this.TrySkip(count * 2, context); diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 092e0973..bb9cd49e 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -57,6 +57,11 @@ public MessagePackStreamingReader(scoped in BufferRefresh refresh) private DecodeResult InsufficientBytes => this.eof ? DecodeResult.EmptyBuffer : DecodeResult.InsufficientBuffer; + public DecodeResult TryPeekNextCode(out byte code) + { + return this.reader.TryPeek(out code) ? DecodeResult.Success : this.InsufficientBytes; + } + public DecodeResult TryReadNil() { if (this.reader.TryPeek(out byte next)) @@ -180,6 +185,36 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + public DecodeResult TryRead(out string? value) + { + DecodeResult result = this.TryReadNil(); + if (result != DecodeResult.TokenMismatch) + { + value = null; + return result; + } + + result = this.TryGetStringLengthInBytes(out uint byteLength); + if (result != DecodeResult.Success) + { + value = null; + return result; + } + + ReadOnlySpan unreadSpan = this.reader.UnreadSpan; + if (unreadSpan.Length >= byteLength) + { + // Fast path: all bytes to decode appear in the same span. + value = StringEncoding.UTF8.GetString(unreadSpan.Slice(0, checked((int)byteLength))); + this.reader.Advance(byteLength); + return DecodeResult.Success; + } + else + { + return this.ReadStringSlow(byteLength, out value); + } + } + public DecodeResult TryRead(out DateTime value) { DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); @@ -395,6 +430,40 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan value) + { + SequenceReader oldReader = this.reader; + DecodeResult result = this.TryGetStringLengthInBytes(out uint length); + if (result != DecodeResult.Success) + { + value = default; + contiguous = false; + return result; + } + + if (this.reader.Remaining < length) + { + value = default; + contiguous = false; + return this.InsufficientBytes; + } + + if (this.reader.CurrentSpanIndex + length <= this.reader.CurrentSpan.Length) + { + value = this.reader.CurrentSpan.Slice(this.reader.CurrentSpanIndex, checked((int)length)); + this.reader.Advance(length); + contiguous = true; + return DecodeResult.Success; + } + else + { + this.reader = oldReader; + value = default; + contiguous = false; + return DecodeResult.Success; + } + } + /// /// Gets the information to return from an async method that has been using this reader /// so that the caller knows how to resume reading. @@ -450,6 +519,81 @@ static async ValueTask Helper(GetMoreBytesAsync getMoreBytes, obj [DoesNotReturn] private static DecodeResult ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + private DecodeResult TryGetStringLengthInBytes(out uint length) + { + DecodeResult readResult = MessagePackPrimitives.TryReadStringHeader(this.reader.UnreadSpan, out length, out int tokenSize); + if (readResult == DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, ref length, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult readResult, ref uint length, ref int tokenSize) + { + switch (readResult) + { + case DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case DecodeResult.TokenMismatch: + return DecodeResult.TokenMismatch; + case DecodeResult.EmptyBuffer: + case DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = MessagePackPrimitives.TryReadStringHeader(buffer, out length, out tokenSize); + return SlowPath(ref self, readResult, ref length, ref tokenSize); + } + else + { + length = default; + return DecodeResult.InsufficientBuffer; + } + + default: + return ThrowUnreachable(); + } + } + } + + /// + /// Reads a string assuming that it is spread across multiple spans in the . + /// + /// The length of the string to be decoded, in bytes. + /// Receives the decoded string. + /// The result of the operation. + private DecodeResult ReadStringSlow(uint byteLength, out string? value) + { + if (this.reader.Remaining < byteLength) + { + value = null; + return this.InsufficientBytes; + } + + // We need to decode bytes incrementally across multiple spans. + int remainingByteLength = checked((int)byteLength); + int maxCharLength = StringEncoding.UTF8.GetMaxCharCount(remainingByteLength); + char[] charArray = ArrayPool.Shared.Rent(maxCharLength); + System.Text.Decoder decoder = StringEncoding.UTF8.GetDecoder(); + + int initializedChars = 0; + while (remainingByteLength > 0) + { + int bytesRead = Math.Min(remainingByteLength, this.reader.UnreadSpan.Length); + remainingByteLength -= bytesRead; + bool flush = remainingByteLength == 0; + initializedChars += decoder.GetChars(this.reader.UnreadSpan.Slice(0, bytesRead), charArray.AsSpan(initializedChars), flush); + this.reader.Advance(bytesRead); + } + + value = new string(charArray, 0, initializedChars); + ArrayPool.Shared.Return(charArray); + return DecodeResult.Success; + } + public struct BufferRefresh { internal CancellationToken CancellationToken { get; init; } From 806f55e9b47dc58568c95f16a2f47a12150b7eec Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Nov 2024 21:55:30 -0700 Subject: [PATCH 07/20] Move extension reading --- src/Nerdbank.MessagePack/MessagePackReader.cs | 21 +++++++++-------- .../MessagePackStreamingReader.cs | 23 ++++++++++++++++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 88a5ab85..622aca71 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -596,7 +596,7 @@ public ExtensionHeader ReadExtensionHeader() /// Thrown if a code other than an extension format header is encountered. public bool TryReadExtensionHeader(out ExtensionHeader extensionHeader) { - switch (this.streamingReader.TryReadExtensionHeader(out extensionHeader)) + switch (this.streamingReader.TryRead(out extensionHeader)) { case MessagePackPrimitives.DecodeResult.Success: return true; @@ -627,16 +627,17 @@ public bool TryReadExtensionHeader(out ExtensionHeader extensionHeader) /// public Extension ReadExtension() { - ExtensionHeader header = this.ReadExtensionHeader(); - try + switch (this.streamingReader.TryRead(out Extension value)) { - ReadOnlySequence data = this.reader.Sequence.Slice(this.reader.Position, header.Length); - this.reader.Advance(header.Length); - return new Extension(header.TypeCode, data); - } - catch (ArgumentOutOfRangeException ex) - { - throw ThrowNotEnoughBytesException(ex); + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index bb9cd49e..630ccda8 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -390,7 +390,7 @@ public DecodeResult TryReadRaw(long length, out ReadOnlySequence rawMsgPac return this.InsufficientBytes; } - public DecodeResult TryReadExtensionHeader(out ExtensionHeader extensionHeader) + public DecodeResult TryRead(out ExtensionHeader extensionHeader) { DecodeResult readResult = MessagePackPrimitives.TryReadExtensionHeader(this.reader.UnreadSpan, out extensionHeader, out int tokenSize); if (readResult == DecodeResult.Success) @@ -430,6 +430,27 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + public DecodeResult TryRead(out Extension extension) + { + DecodeResult result = this.TryRead(out ExtensionHeader header); + if (result != DecodeResult.Success) + { + extension = default; + return result; + } + + if (this.reader.Remaining < header.Length) + { + extension = default; + return this.InsufficientBytes; + } + + ReadOnlySequence data = this.reader.Sequence.Slice(this.reader.Position, header.Length); + this.reader.Advance(header.Length); + extension = new Extension(header.TypeCode, data); + return DecodeResult.Success; + } + public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan value) { SequenceReader oldReader = this.reader; From 35446833f117e4dedb6fa832b49c763c74a70217 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 28 Nov 2024 05:54:18 -0700 Subject: [PATCH 08/20] Move TrySkip --- src/Nerdbank.MessagePack/MessagePackReader.cs | 84 +-------- .../MessagePackStreamingReader.cs | 172 ++++++++++++++++++ 2 files changed, 181 insertions(+), 75 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 622aca71..aa50e165 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // This file was originally derived from https://github.com/MessagePack-CSharp/MessagePack-CSharp/ -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -664,65 +663,17 @@ internal static Exception ThrowInvalidCode(byte code) /// internal bool TrySkip(SerializationContext context) { - if (this.reader.Remaining == 0) + switch (this.streamingReader.TrySkip(context)) { - return false; - } - - byte code = this.NextCode; - switch (code) - { - case byte x when MessagePackCode.IsPositiveFixInt(x) || MessagePackCode.IsNegativeFixInt(x): - case MessagePackCode.Nil: - case MessagePackCode.True: - case MessagePackCode.False: - return this.reader.TryAdvance(1); - case MessagePackCode.Int8: - case MessagePackCode.UInt8: - return this.reader.TryAdvance(2); - case MessagePackCode.Int16: - case MessagePackCode.UInt16: - return this.reader.TryAdvance(3); - case MessagePackCode.Int32: - case MessagePackCode.UInt32: - case MessagePackCode.Float32: - return this.reader.TryAdvance(5); - case MessagePackCode.Int64: - case MessagePackCode.UInt64: - case MessagePackCode.Float64: - return this.reader.TryAdvance(9); - case byte x when MessagePackCode.IsFixMap(x): - case MessagePackCode.Map16: - case MessagePackCode.Map32: - context.DepthStep(); - return this.TrySkipNextMap(context); - case byte x when MessagePackCode.IsFixArray(x): - case MessagePackCode.Array16: - case MessagePackCode.Array32: - context.DepthStep(); - return this.TrySkipNextArray(context); - case byte x when MessagePackCode.IsFixStr(x): - case MessagePackCode.Str8: - case MessagePackCode.Str16: - case MessagePackCode.Str32: - return this.TryGetStringLengthInBytes(out uint length) && this.reader.TryAdvance(length); - case MessagePackCode.Bin8: - case MessagePackCode.Bin16: - case MessagePackCode.Bin32: - return this.TryGetBytesLength(out length) && this.reader.TryAdvance(length); - case MessagePackCode.FixExt1: - case MessagePackCode.FixExt2: - case MessagePackCode.FixExt4: - case MessagePackCode.FixExt8: - case MessagePackCode.FixExt16: - case MessagePackCode.Ext8: - case MessagePackCode.Ext16: - case MessagePackCode.Ext32: - return this.TryReadExtensionHeader(out ExtensionHeader header) && this.reader.TryAdvance(header.Length); + case MessagePackPrimitives.DecodeResult.Success: + return true; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + return false; default: - // We don't actually expect to ever hit this point, since every code is supported. - Debug.Fail("Missing handler for code: " + code); - throw ThrowInvalidCode(code); + throw ThrowUnreachable(); } } @@ -868,21 +819,4 @@ private uint GetStringLengthInBytes() ThrowInsufficientBufferUnless(this.TryGetStringLengthInBytes(out uint length)); return length; } - - private bool TrySkipNextArray(SerializationContext context) => this.TryReadArrayHeader(out int count) && this.TrySkip(count, context); - - private bool TrySkipNextMap(SerializationContext context) => this.TryReadMapHeader(out int count) && this.TrySkip(count * 2, context); - - private bool TrySkip(int count, SerializationContext context) - { - for (int i = 0; i < count; i++) - { - if (!this.TrySkip(context)) - { - return false; - } - } - - return true; - } } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 630ccda8..a1e29147 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -1,6 +1,7 @@ // Copyright (c) Andrew Arnott. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO.Pipelines; using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; @@ -485,6 +486,124 @@ public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan /// Gets the information to return from an async method that has been using this reader /// so that the caller knows how to resume reading. @@ -540,6 +659,59 @@ static async ValueTask Helper(GetMoreBytesAsync getMoreBytes, obj [DoesNotReturn] private static DecodeResult ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + private DecodeResult TryGetBytesLength(out uint length) + { + bool usingBinaryHeader = true; + MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadBinHeader(this.reader.UnreadSpan, out length, out int tokenSize); + if (readResult == MessagePackPrimitives.DecodeResult.Success) + { + this.reader.Advance(tokenSize); + return DecodeResult.Success; + } + + return SlowPath(ref this, readResult, usingBinaryHeader, ref length, ref tokenSize); + + static DecodeResult SlowPath(ref MessagePackStreamingReader self, MessagePackPrimitives.DecodeResult readResult, bool usingBinaryHeader, ref uint length, ref int tokenSize) + { + switch (readResult) + { + case MessagePackPrimitives.DecodeResult.Success: + self.reader.Advance(tokenSize); + return DecodeResult.Success; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + if (usingBinaryHeader) + { + usingBinaryHeader = false; + readResult = MessagePackPrimitives.TryReadStringHeader(self.reader.UnreadSpan, out length, out tokenSize); + return SlowPath(ref self, readResult, usingBinaryHeader, ref length, ref tokenSize); + } + else + { + return DecodeResult.TokenMismatch; + } + + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + Span buffer = stackalloc byte[tokenSize]; + if (self.reader.TryCopyTo(buffer)) + { + readResult = usingBinaryHeader + ? MessagePackPrimitives.TryReadBinHeader(buffer, out length, out tokenSize) + : MessagePackPrimitives.TryReadStringHeader(buffer, out length, out tokenSize); + return SlowPath(ref self, readResult, usingBinaryHeader, ref length, ref tokenSize); + } + else + { + length = default; + return self.InsufficientBytes; + } + + default: + return ThrowUnreachable(); + } + } + } + private DecodeResult TryGetStringLengthInBytes(out uint length) { DecodeResult readResult = MessagePackPrimitives.TryReadStringHeader(this.reader.UnreadSpan, out length, out int tokenSize); From 63cc7b4c5ca4f92d078e41370884ea8f77633fbb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 28 Nov 2024 06:04:30 -0700 Subject: [PATCH 09/20] Move read binary and string sequences --- src/Nerdbank.MessagePack/MessagePackReader.cs | 52 +++++---- .../MessagePackStreamingReader.cs | 108 ++++++++++++------ 2 files changed, 104 insertions(+), 56 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index aa50e165..abe18882 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -450,16 +450,23 @@ public DateTime ReadDateTime(ExtensionHeader header) /// public ReadOnlySequence? ReadBytes() { - if (this.TryReadNil()) + switch (this.streamingReader.TryReadBinary(out ReadOnlySequence value)) { - return null; - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + if (this.TryReadNil()) + { + return null; + } - uint length = this.GetBytesLength(); - ThrowInsufficientBufferUnless(this.reader.Remaining >= length); - ReadOnlySequence result = this.reader.Sequence.Slice(this.reader.Position, length); - this.reader.Advance(length); - return result; + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); + } } /// @@ -475,16 +482,23 @@ public DateTime ReadDateTime(ExtensionHeader header) /// public ReadOnlySequence? ReadStringSequence() { - if (this.TryReadNil()) + switch (this.streamingReader.TryReadStringSequence(out ReadOnlySequence value)) { - return null; - } + case MessagePackPrimitives.DecodeResult.Success: + return value; + case MessagePackPrimitives.DecodeResult.TokenMismatch: + if (this.TryReadNil()) + { + return null; + } - uint length = this.GetStringLengthInBytes(); - ThrowInsufficientBufferUnless(this.reader.Remaining >= length); - ReadOnlySequence result = this.reader.Sequence.Slice(this.reader.Position, length); - this.reader.Advance(length); - return result; + throw ThrowInvalidCode(this.NextCode); + case MessagePackPrimitives.DecodeResult.EmptyBuffer: + case MessagePackPrimitives.DecodeResult.InsufficientBuffer: + throw ThrowNotEnoughBytesException(); + default: + throw ThrowUnreachable(); + } } /// @@ -683,12 +697,6 @@ internal bool TrySkip(SerializationContext context) /// private static EndOfStreamException ThrowNotEnoughBytesException() => throw new EndOfStreamException(); - /// - /// Throws an exception indicating that there aren't enough bytes remaining in the buffer to store - /// the promised data. - /// - private static EndOfStreamException ThrowNotEnoughBytesException(Exception innerException) => throw new EndOfStreamException(new EndOfStreamException().Message, innerException); - /// /// Throws if a condition is false. /// diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index a1e29147..0cccb557 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -391,6 +391,80 @@ public DecodeResult TryReadRaw(long length, out ReadOnlySequence rawMsgPac return this.InsufficientBytes; } + public DecodeResult TryReadBinary(out ReadOnlySequence value) + { + DecodeResult result = this.TryGetBytesLength(out uint length); + if (result != DecodeResult.Success) + { + value = default; + return result; + } + + if (this.reader.Remaining < length) + { + value = default; + return this.InsufficientBytes; + } + + value = this.reader.Sequence.Slice(this.reader.Position, length); + this.reader.Advance(length); + return DecodeResult.Success; + } + + public DecodeResult TryReadStringSequence(out ReadOnlySequence value) + { + DecodeResult result = this.TryGetStringLengthInBytes(out uint length); + if (result != DecodeResult.Success) + { + value = default; + return result; + } + + if (this.reader.Remaining < length) + { + value = default; + return this.InsufficientBytes; + } + + value = this.reader.Sequence.Slice(this.reader.Position, length); + this.reader.Advance(length); + return DecodeResult.Success; + } + + public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan value) + { + SequenceReader oldReader = this.reader; + DecodeResult result = this.TryGetStringLengthInBytes(out uint length); + if (result != DecodeResult.Success) + { + value = default; + contiguous = false; + return result; + } + + if (this.reader.Remaining < length) + { + value = default; + contiguous = false; + return this.InsufficientBytes; + } + + if (this.reader.CurrentSpanIndex + length <= this.reader.CurrentSpan.Length) + { + value = this.reader.CurrentSpan.Slice(this.reader.CurrentSpanIndex, checked((int)length)); + this.reader.Advance(length); + contiguous = true; + return DecodeResult.Success; + } + else + { + this.reader = oldReader; + value = default; + contiguous = false; + return DecodeResult.Success; + } + } + public DecodeResult TryRead(out ExtensionHeader extensionHeader) { DecodeResult readResult = MessagePackPrimitives.TryReadExtensionHeader(this.reader.UnreadSpan, out extensionHeader, out int tokenSize); @@ -452,40 +526,6 @@ public DecodeResult TryRead(out Extension extension) return DecodeResult.Success; } - public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan value) - { - SequenceReader oldReader = this.reader; - DecodeResult result = this.TryGetStringLengthInBytes(out uint length); - if (result != DecodeResult.Success) - { - value = default; - contiguous = false; - return result; - } - - if (this.reader.Remaining < length) - { - value = default; - contiguous = false; - return this.InsufficientBytes; - } - - if (this.reader.CurrentSpanIndex + length <= this.reader.CurrentSpan.Length) - { - value = this.reader.CurrentSpan.Slice(this.reader.CurrentSpanIndex, checked((int)length)); - this.reader.Advance(length); - contiguous = true; - return DecodeResult.Success; - } - else - { - this.reader = oldReader; - value = default; - contiguous = false; - return DecodeResult.Success; - } - } - public DecodeResult TrySkip(SerializationContext context) { DecodeResult result = this.TryPeekNextCode(out byte code); From 8d8bdc71da522f0925f28bf2ee3cadcb17d9afcd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 28 Nov 2024 06:12:27 -0700 Subject: [PATCH 10/20] Move and remove dead code --- src/Nerdbank.MessagePack/MessagePackReader.cs | 140 ++---------------- 1 file changed, 13 insertions(+), 127 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index abe18882..ffed35c7 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -38,28 +38,25 @@ public MessagePackReader(scoped in ReadOnlySequence msgpack) this.streamingReader = new(msgpack, null, null); } - [UnscopedRef] - private ref SequenceReader reader => ref this.streamingReader.SequenceReader; - /// /// Gets the originally supplied to the constructor. /// - public ReadOnlySequence Sequence => this.reader.Sequence; + public ReadOnlySequence Sequence => this.streamingReader.SequenceReader.Sequence; /// /// Gets the current position of the reader within . /// - public SequencePosition Position => this.reader.Position; + public SequencePosition Position => this.streamingReader.SequenceReader.Position; /// /// Gets the number of bytes consumed by the reader. /// - public long Consumed => this.reader.Consumed; + public long Consumed => this.streamingReader.SequenceReader.Consumed; /// /// Gets a value indicating whether the reader is at the end of the sequence. /// - public bool End => this.reader.End; + public bool End => this.streamingReader.SequenceReader.End; /// /// Gets a value indicating whether the reader position is pointing at a nil value. @@ -83,8 +80,12 @@ public byte NextCode { get { - ThrowInsufficientBufferUnless(this.reader.TryPeek(out byte code)); - return code; + return this.streamingReader.TryPeekNextCode(out byte code) switch + { + MessagePackPrimitives.DecodeResult.Success => code, + MessagePackPrimitives.DecodeResult.EmptyBuffer or MessagePackPrimitives.DecodeResult.InsufficientBuffer => throw ThrowNotEnoughBytesException(), + _ => throw ThrowUnreachable(), + }; } } @@ -212,7 +213,7 @@ public int ReadArrayHeader() // Protect against corrupted or mischievous data that may lead to allocating way too much memory. // We allow for each primitive to be the minimal 1 byte in size. // Formatters that know each element is larger can optionally add a stronger check. - ThrowInsufficientBufferUnless(this.reader.Remaining >= count); + ThrowInsufficientBufferUnless(this.streamingReader.SequenceReader.Remaining >= count); return count; } @@ -264,7 +265,7 @@ public int ReadMapHeader() // Protect against corrupted or mischievous data that may lead to allocating way too much memory. // We allow for each primitive to be the minimal 1 byte in size, and we have a key=value map, so that's 2 bytes. // Formatters that know each element is larger can optionally add a stronger check. - ThrowInsufficientBufferUnless(this.reader.Remaining >= count * 2); + ThrowInsufficientBufferUnless(this.streamingReader.SequenceReader.Remaining >= count * 2); return count; } @@ -587,7 +588,7 @@ public ExtensionHeader ReadExtensionHeader() ThrowInsufficientBufferUnless(this.TryReadExtensionHeader(out ExtensionHeader header)); // Protect against corrupted or mischievous data that may lead to allocating way too much memory. - ThrowInsufficientBufferUnless(this.reader.Remaining >= header.Length); + ThrowInsufficientBufferUnless(this.streamingReader.SequenceReader.Remaining >= header.Length); return header; } @@ -712,119 +713,4 @@ private static void ThrowInsufficientBufferUnless(bool condition) [DoesNotReturn] private static Exception ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); - - private uint GetBytesLength() - { - ThrowInsufficientBufferUnless(this.TryGetBytesLength(out uint length)); - return length; - } - - private bool TryGetBytesLength(out uint length) - { - bool usingBinaryHeader = true; - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadBinHeader(this.reader.UnreadSpan, out length, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return true; - } - - return SlowPath(ref this, readResult, usingBinaryHeader, ref length, ref tokenSize); - - static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, bool usingBinaryHeader, ref uint length, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return true; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - if (usingBinaryHeader) - { - usingBinaryHeader = false; - readResult = MessagePackPrimitives.TryReadStringHeader(self.reader.UnreadSpan, out length, out tokenSize); - return SlowPath(ref self, readResult, usingBinaryHeader, ref length, ref tokenSize); - } - else - { - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - } - - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = usingBinaryHeader - ? MessagePackPrimitives.TryReadBinHeader(buffer, out length, out tokenSize) - : MessagePackPrimitives.TryReadStringHeader(buffer, out length, out tokenSize); - return SlowPath(ref self, readResult, usingBinaryHeader, ref length, ref tokenSize); - } - else - { - length = default; - return false; - } - - default: - throw ThrowUnreachable(); - } - } - } - - /// - /// Gets the length of the next string. - /// - /// Receives the length of the next string, if there were enough bytes to read it. - /// if there were enough bytes to read the length of the next string; otherwise. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool TryGetStringLengthInBytes(out uint length) - { - MessagePackPrimitives.DecodeResult readResult = MessagePackPrimitives.TryReadStringHeader(this.reader.UnreadSpan, out length, out int tokenSize); - if (readResult == MessagePackPrimitives.DecodeResult.Success) - { - this.reader.Advance(tokenSize); - return true; - } - - return SlowPath(ref this, readResult, ref length, ref tokenSize); - - static bool SlowPath(ref MessagePackReader self, MessagePackPrimitives.DecodeResult readResult, ref uint length, ref int tokenSize) - { - switch (readResult) - { - case MessagePackPrimitives.DecodeResult.Success: - self.reader.Advance(tokenSize); - return true; - case MessagePackPrimitives.DecodeResult.TokenMismatch: - throw ThrowInvalidCode(self.reader.UnreadSpan[0]); - case MessagePackPrimitives.DecodeResult.EmptyBuffer: - case MessagePackPrimitives.DecodeResult.InsufficientBuffer: - Span buffer = stackalloc byte[tokenSize]; - if (self.reader.TryCopyTo(buffer)) - { - readResult = MessagePackPrimitives.TryReadStringHeader(buffer, out length, out tokenSize); - return SlowPath(ref self, readResult, ref length, ref tokenSize); - } - else - { - length = default; - return false; - } - - default: - throw ThrowUnreachable(); - } - } - } - - /// - /// Gets the length of the next string. - /// - /// The length of the next string. - private uint GetStringLengthInBytes() - { - ThrowInsufficientBufferUnless(this.TryGetStringLengthInBytes(out uint length)); - return length; - } } From 597188340b05ac3ec64c7b40ebd479c0641118cf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 29 Nov 2024 07:19:47 -0700 Subject: [PATCH 11/20] Add a sample of the best we can do --- .../DecodeResultExtensions.cs | 35 +++++++++++++++++++ .../MessagePackPrimitives.Writers.cs | 3 +- src/Nerdbank.MessagePack/MessagePackReader.cs | 3 +- .../MessagePackStreamingReader.cs | 3 +- .../MessagePackStreamingReaderTests.cs | 31 ++++++++++++++++ 5 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/Nerdbank.MessagePack/DecodeResultExtensions.cs diff --git a/src/Nerdbank.MessagePack/DecodeResultExtensions.cs b/src/Nerdbank.MessagePack/DecodeResultExtensions.cs new file mode 100644 index 00000000..eadeed16 --- /dev/null +++ b/src/Nerdbank.MessagePack/DecodeResultExtensions.cs @@ -0,0 +1,35 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using static Nerdbank.MessagePack.MessagePackPrimitives; + +namespace Nerdbank.MessagePack; + +/// +/// Extension methods for the enum. +/// +public static class DecodeResultExtensions +{ + /// + /// Processes a given value and returns a boolean indicating whether more bytes are needed. + /// + /// The value. + /// + /// if the value is ; + /// if the value is . + /// + /// Thrown if the value is . + /// Thrown if the value is . + public static bool NeedsMoreBytes(this DecodeResult result) + { + return result switch + { + DecodeResult.Success => false, + DecodeResult.InsufficientBuffer => true, + DecodeResult.EmptyBuffer => throw new EndOfStreamException(), + DecodeResult.TokenMismatch => throw new MessagePackSerializationException("Unexpected token encountered."), // TODO: Include the unexpected token into the exception message by packing MessagePackType into the DecodeResult. + _ => throw new UnreachableException(), + }; + } +} diff --git a/src/Nerdbank.MessagePack/MessagePackPrimitives.Writers.cs b/src/Nerdbank.MessagePack/MessagePackPrimitives.Writers.cs index f3aa431a..1d87f2d9 100644 --- a/src/Nerdbank.MessagePack/MessagePackPrimitives.Writers.cs +++ b/src/Nerdbank.MessagePack/MessagePackPrimitives.Writers.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Buffers.Binary; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1100,7 +1101,7 @@ private static bool TryWriteNegativeFixIntUnsafe(Span destination, sbyte v } [DoesNotReturn] - private static Exception ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + private static Exception ThrowUnreachable() => throw new UnreachableException(); /// /// Writes an integer value in big-endian order to the specified buffer. diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index ffed35c7..913e9e87 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // This file was originally derived from https://github.com/MessagePack-CSharp/MessagePack-CSharp/ +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -712,5 +713,5 @@ private static void ThrowInsufficientBufferUnless(bool condition) } [DoesNotReturn] - private static Exception ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + private static Exception ThrowUnreachable() => throw new UnreachableException(); } diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 0cccb557..38746bbd 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -29,7 +29,6 @@ public MessagePackStreamingReader(scoped in ReadOnlySequence sequence, Get this.reader = new SequenceReader(sequence); this.getMoreBytesAsync = additionalBytesSource; this.getMoreBytesState = getMoreBytesState; - ; } public MessagePackStreamingReader(scoped in BufferRefresh refresh) @@ -697,7 +696,7 @@ static async ValueTask Helper(GetMoreBytesAsync getMoreBytes, obj } [DoesNotReturn] - private static DecodeResult ThrowUnreachable() => throw new Exception("Presumed unreachable point in code reached."); + private static DecodeResult ThrowUnreachable() => throw new UnreachableException(); private DecodeResult TryGetBytesLength(out uint length) { diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index 9e15f87d..540da86e 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -79,4 +79,35 @@ private static ReadOnlySequence CreateMsgPackArrayOf3Bools() return seq; } + + // TODO: Remove/move this sample + [MessagePackConverter(typeof(SomeTypeConverter))] + record SomeType(string Message, int Number); + + class SomeTypeConverter + { + internal async ValueTask<(SomeType, MessagePackStreamingReader.BufferRefresh)> Read(MessagePackStreamingReader.BufferRefresh readerInputs) + { + MessagePackStreamingReader reader = new(readerInputs); + + while (reader.TryReadArrayHeader(out int count).NeedsMoreBytes()) + { + reader = new(await reader.ReplenishBufferAsync()); + } + + string? str; + while (reader.TryRead(out str).NeedsMoreBytes()) + { + reader = new(await reader.ReplenishBufferAsync()); + } + + int num; + while (reader.TryRead(out num).NeedsMoreBytes()) + { + reader = new(await reader.ReplenishBufferAsync()); + } + + return (new SomeType(str, num), reader.GetExchangeInfo()); + } + } } From 3c7b85660778fc6ac7b8923af6b9cabb7b4981b4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 30 Nov 2024 09:57:32 -0700 Subject: [PATCH 12/20] Add a more discoverable way to get the reader --- src/Nerdbank.MessagePack/MessagePackStreamingReader.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index 38746bbd..7e1a6a7b 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -837,5 +837,7 @@ public struct BufferRefresh internal object? GetMoreBytesState { get; init; } internal bool EndOfStream { get; init; } + + public MessagePackStreamingReader CreateReader() => new(this); } } From e17e3119960fab76ab1119524241b6d14081c34d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 30 Nov 2024 11:12:03 -0700 Subject: [PATCH 13/20] Fix typo in code comment --- src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs | 2 +- .../Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs | 2 +- .../Converters/ObjectMapWithNonDefaultCtorConverter`2.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs index dd0aa0dc..19010433 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs @@ -342,7 +342,7 @@ int NextSyncBatchSize() { int mapEntries = await reader.ReadMapHeaderAsync().ConfigureAwait(false); - // We're going to read in bursts. Anything we happen to get in one buffer, we'll ready synchronously regardless of whether the property is async. + // We're going to read in bursts. Anything we happen to get in one buffer, we'll read synchronously regardless of whether the property is async. // But when we run out of buffer, if the next thing to read is async, we'll read it async. int remainingEntries = mapEntries; while (remainingEntries > 0) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs index a2bbd05e..86eb99a9 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs @@ -93,7 +93,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter 0) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs index 9850b0d8..75691212 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs @@ -81,7 +81,7 @@ internal class ObjectMapWithNonDefaultCtorConverter 0) From 11df823625c3d9d5978b2efc489cd30d1361d943 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 7 Dec 2024 18:09:50 -0700 Subject: [PATCH 14/20] Improve merge --- .../AnalyzerReleases.Unshipped.md | 2 -- src/Nerdbank.MessagePack.Analyzers/ConverterAnalyzers.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Nerdbank.MessagePack.Analyzers/AnalyzerReleases.Unshipped.md b/src/Nerdbank.MessagePack.Analyzers/AnalyzerReleases.Unshipped.md index 5feb5910..97ae3979 100644 --- a/src/Nerdbank.MessagePack.Analyzers/AnalyzerReleases.Unshipped.md +++ b/src/Nerdbank.MessagePack.Analyzers/AnalyzerReleases.Unshipped.md @@ -17,8 +17,6 @@ NBMsgPack021 | Usage | Error | `[MessagePackConverter]` type missing default con NBMsgPack030 | Usage | Warning | Converters should not call top-level `MessagePackSerializer` methods NBMsgPack031 | Usage | Warning | Converters should read or write exactly one msgpack structure NBMsgPack032 | Usage | Info | Converters should override GetJsonSchema -NBMsgPack033 | Usage | Error | Async converters should return readers before any await (control flow analyzer) -NBMsgPack034 | Usage | Error | Async converters should not reuse readers after returning them (control flow analyzer) NBMsgPack100 | Migration | Info | Migrate MessagePack-CSharp formatter NBMsgPack101 | Migration | Info | Migrate to MessagePackConverterAttribute NBMsgPack102 | Migration | Info | Remove use of MessagePackObjectAttribute diff --git a/src/Nerdbank.MessagePack.Analyzers/ConverterAnalyzers.cs b/src/Nerdbank.MessagePack.Analyzers/ConverterAnalyzers.cs index 0c73f74d..8f9b29d6 100644 --- a/src/Nerdbank.MessagePack.Analyzers/ConverterAnalyzers.cs +++ b/src/Nerdbank.MessagePack.Analyzers/ConverterAnalyzers.cs @@ -16,6 +16,9 @@ public class ConverterAnalyzers : DiagnosticAnalyzer public const string OverrideGetJsonSchemaDiagnosticId = "NBMsgPack032"; //// NBMsgPack033 | Usage | Error | Async converters should return the MessagePackWriter + //// NBMsgPack034 | Usage | Error | Async converters should not reuse MessagePackWriter after returning it + //// NBMsgPack035 | Usage | Error | Async converters should return readers before any await(control flow analyzer) + //// NBMsgPack036 | Usage | Error | Async converters should not reuse readers after returning them (control flow analyzer)/ public static readonly DiagnosticDescriptor CallbackToTopLevelSerializerDescriptor = new( CallbackToTopLevelSerializerDiagnosticId, From 06efe2eca54481f95e8991d8fc7103d5c27638a0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 13:50:26 -0700 Subject: [PATCH 15/20] Fix test failures --- src/Nerdbank.MessagePack/MessagePackSerializer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackSerializer.cs b/src/Nerdbank.MessagePack/MessagePackSerializer.cs index 0ef3b241..e381249f 100644 --- a/src/Nerdbank.MessagePack/MessagePackSerializer.cs +++ b/src/Nerdbank.MessagePack/MessagePackSerializer.cs @@ -370,12 +370,14 @@ public async ValueTask SerializeAsync(PipeWriter writer, T? value, ITypeShape /// /// A cancellation token. /// The deserialized value. - public ValueTask DeserializeAsync(PipeReader reader, ITypeShapeProvider provider, CancellationToken cancellationToken = default) + public async ValueTask DeserializeAsync(PipeReader reader, ITypeShapeProvider provider, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); using DisposableSerializationContext context = this.CreateSerializationContext(provider, cancellationToken); #pragma warning disable NBMsgPackAsync - return this.GetOrAddConverter(provider).ReadAsync(new MessagePackAsyncReader(reader) { CancellationToken = cancellationToken }, context.Value); + var asyncReader = new MessagePackAsyncReader(reader) { CancellationToken = cancellationToken }; + await asyncReader.ReadAsync(); + return await this.GetOrAddConverter(provider).ReadAsync(asyncReader, context.Value); #pragma warning restore NBMsgPackAsync } From dddb25c649b855981cc7411d2e70f149f82d49f7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 16:16:01 -0700 Subject: [PATCH 16/20] Fix all the build warnings --- samples/.editorconfig | 3 + samples/CustomConverters.cs | 47 +++++ .../Converters/ArrayConverter`1.cs | 4 +- .../Converters/DictionaryConverter`3.cs | 6 +- .../Converters/EnumerableConverter`2.cs | 4 +- .../Converters/ObjectArrayConverter`1.cs | 6 +- ...bjectArrayWithNonDefaultCtorConverter`2.cs | 6 +- .../Converters/ObjectMapConverter`1.cs | 4 +- .../ObjectMapWithNonDefaultCtorConverter`2.cs | 4 +- .../MessagePackAsyncReader.cs | 50 +++-- .../MessagePackConverter`1.cs | 2 +- src/Nerdbank.MessagePack/MessagePackReader.cs | 3 +- .../MessagePackStreamingReader.cs | 179 +++++++++++++++++- src/Nerdbank.MessagePack/StandardVisitor.cs | 2 +- .../net8.0/PublicAPI.Unshipped.txt | 48 ++++- .../netstandard2.0/PublicAPI.Unshipped.txt | 48 ++++- .../MessagePackStreamingReaderTests.cs | 2 + 17 files changed, 365 insertions(+), 53 deletions(-) diff --git a/samples/.editorconfig b/samples/.editorconfig index 4afec869..b6e51e84 100644 --- a/samples/.editorconfig +++ b/samples/.editorconfig @@ -52,3 +52,6 @@ dotnet_diagnostic.CS1591.severity = silent # CA1822: Mark members as static dotnet_diagnostic.CA1822.severity = silent + +# CA1062: Validate arguments of public methods +dotnet_diagnostic.CA1062.severity = silent diff --git a/samples/CustomConverters.cs b/samples/CustomConverters.cs index 252437d0..ed57a789 100644 --- a/samples/CustomConverters.cs +++ b/samples/CustomConverters.cs @@ -1,6 +1,8 @@ // Copyright (c) Andrew Arnott. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace CustomConverter { #region YourOwnConverter @@ -329,3 +331,48 @@ void Main() } } } + +namespace AsyncConverters +{ + [MessagePackConverter(typeof(MyCustomTypeConverter))] + public class MyCustomType { } + + public class MyCustomTypeConverter : MessagePackConverter + { + public override MyCustomType? Read(ref MessagePackReader reader, SerializationContext context) + { + throw new NotImplementedException(); + } + + public override void Write(ref MessagePackWriter writer, in MyCustomType? value, SerializationContext context) + { + throw new NotImplementedException(); + } + + [Experimental("NBMsgPack")] + public override async ValueTask ReadAsync(MessagePackAsyncReader reader, SerializationContext context) + { + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); + + #region GetMoreBytesPattern + int count; + while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) + { + streamingReader = new(await streamingReader.ReplenishBufferAsync()); + } + #endregion + + for (int i = 0; i < count; i++) + { + while (streamingReader.TrySkip(context).NeedsMoreBytes()) + { + streamingReader = new(await streamingReader.ReplenishBufferAsync()); + } + } + + reader.ReturnReader(ref streamingReader); + + return new MyCustomType(); + } + } +} diff --git a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs index 7b3fd5d0..7d6254f0 100644 --- a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs @@ -95,7 +95,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme [Experimental("NBMsgPackAsync")] public override async ValueTask ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -130,7 +130,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme { reader.ReturnReader(ref streamingReader); await reader.BufferNextStructureAsync(context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int count = syncReader.ReadArrayHeader(); TElement[] array = new TElement[count]; diff --git a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs index 3129f5ef..0887fd37 100644 --- a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs +++ b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs @@ -140,7 +140,7 @@ internal class MutableDictionaryConverter( [Experimental("NBMsgPackAsync")] public override async ValueTask ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -178,7 +178,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TDict if (this.ElementPrefersAsyncSerialization) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); int count; while (streamingReader.TryReadMapHeader(out count).NeedsMoreBytes()) { @@ -194,7 +194,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TDict else { await reader.BufferNextStructureAsync(context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int count = syncReader.ReadMapHeader(); for (int i = 0; i < count; i++) { diff --git a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs index e390e8d8..539c7b47 100644 --- a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs @@ -139,7 +139,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TEnum if (this.ElementPrefersAsyncSerialization) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { @@ -154,7 +154,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TEnum else { await reader.BufferNextStructureAsync(context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int count = syncReader.ReadArrayHeader(); for (int i = 0; i < count; i++) { diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs index 52d25758..1e0ac6fb 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs @@ -331,7 +331,7 @@ int NextSyncBatchSize() [Experimental("NBMsgPackAsync")] public override async ValueTask ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -372,7 +372,7 @@ int NextSyncBatchSize() while (remainingEntries > 0) { int bufferedStructures = await reader.BufferNextStructuresAsync(1, remainingEntries * 2, context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int bufferedEntries = bufferedStructures / 2; for (int i = 0; i < bufferedEntries; i++) { @@ -438,7 +438,7 @@ int NextSyncBatchSize() if (syncBatchSize > 0) { await reader.BufferNextStructuresAsync(syncBatchSize, syncBatchSize, context).ConfigureAwait(false); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); for (int syncReadEndExclusive = i + syncBatchSize; i < syncReadEndExclusive; i++) { if (properties.Length > i && properties.Span[i]?.MsgPackReaders is var (deserialize, _)) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs index 01318039..36f487d1 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs @@ -81,7 +81,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -118,7 +118,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter 0) { int bufferedStructures = await reader.BufferNextStructuresAsync(1, remainingEntries * 2, context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int bufferedEntries = bufferedStructures / 2; for (int i = 0; i < bufferedEntries; i++) { @@ -183,7 +183,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter 0) { await reader.BufferNextStructuresAsync(syncBatchSize, syncBatchSize, context).ConfigureAwait(false); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); for (int syncReadEndExclusive = i + syncBatchSize; i < syncReadEndExclusive; i++) { if (parameters.Length > i && parameters[i] is { Read: { } deserialize }) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectMapConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectMapConverter`1.cs index 730b7046..0ff177d6 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectMapConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectMapConverter`1.cs @@ -183,7 +183,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, T? val [Experimental("NBMsgPackAsync")] public override async ValueTask ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -219,7 +219,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, T? val while (remainingEntries > 0) { int bufferedStructures = await reader.BufferNextStructuresAsync(1, remainingEntries * 2, context).ConfigureAwait(false); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int bufferedEntries = bufferedStructures / 2; for (int i = 0; i < bufferedEntries; i++) { diff --git a/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs index fb2c707e..07ee7a53 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectMapWithNonDefaultCtorConverter`2.cs @@ -69,7 +69,7 @@ internal class ObjectMapWithNonDefaultCtorConverter ReadAsync(MessagePackAsyncReader reader, SerializationContext context) { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { @@ -100,7 +100,7 @@ internal class ObjectMapWithNonDefaultCtorConverter 0) { int bufferedStructures = await reader.BufferNextStructuresAsync(1, remainingEntries * 2, context).ConfigureAwait(false); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); int bufferedEntries = bufferedStructures / 2; for (int i = 0; i < bufferedEntries; i++) { diff --git a/src/Nerdbank.MessagePack/MessagePackAsyncReader.cs b/src/Nerdbank.MessagePack/MessagePackAsyncReader.cs index b6b37c31..2892869c 100644 --- a/src/Nerdbank.MessagePack/MessagePackAsyncReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackAsyncReader.cs @@ -33,6 +33,8 @@ public class MessagePackAsyncReader(PipeReader pipeReader) /// public required CancellationToken CancellationToken { get; init; } + private MessagePackStreamingReader.BufferRefresh Refresh => this.refresh ?? throw new InvalidOperationException($"Call {nameof(this.ReadAsync)} first."); + /// /// Gets the fully-capable, synchronous reader. /// @@ -43,9 +45,6 @@ public class MessagePackAsyncReader(PipeReader pipeReader) /// The buffer, for use in creating a , which will contain at least top-level structures and may include more. /// Also returns the number of top-level structures included in the buffer that were counted (up to ). /// - /// - /// The caller must take care to call with before any other methods on this class after this call. - /// /// Thrown if is canceled or returns a result where is . /// Thrown if returns a result where is and yet the buffer is not sufficient to satisfy . public async ValueTask BufferNextStructuresAsync(int minimumDesiredBufferedStructures, int countUpTo, SerializationContext context) @@ -98,6 +97,12 @@ public async ValueTask BufferNextStructuresAsync(int minimumDesiredBuffered /// public async ValueTask BufferNextStructureAsync(SerializationContext context) => await this.BufferNextStructuresAsync(1, 1, context).ConfigureAwait(false); + /// + /// Fills the buffer with msgpack bytes to decode. + /// If the buffer already has bytes, more will be retrieved and added. + /// + /// An async task. + /// Thrown if is canceled. public async ValueTask ReadAsync() { this.ThrowIfReaderNotReturned(); @@ -129,20 +134,44 @@ public async ValueTask ReadAsync() } } - public MessagePackStreamingReader CreateReader() + /// + /// Retrieves a , which is suitable for + /// decoding msgpack from a buffer without throwing any exceptions, even if the buffer is incomplete. + /// + /// A . + /// + /// The result must be returned with + /// before using this again. + /// + public MessagePackStreamingReader CreateStreamingReader() { - ThrowIfReaderNotReturned(); + this.ThrowIfReaderNotReturned(); this.readerReturned = false; return new(this.Refresh); } - public MessagePackReader CreateReader2() + /// + /// Retrieves a , which is suitable for + /// decoding msgpack from a buffer that is known to have enough bytes for the decoding. + /// + /// A . + /// + /// The result must be returned with + /// before using this again. + /// + public MessagePackReader CreateBufferedReader() { - ThrowIfReaderNotReturned(); + this.ThrowIfReaderNotReturned(); this.readerReturned = false; return new(this.Refresh.Buffer); } + /// + /// Returns a previously obtained reader when the caller is done using it, + /// and applies the given reader's position to this reader so that + /// future reads move continuously forward in the msgpack stream. + /// + /// The reader to return. public void ReturnReader(ref MessagePackStreamingReader reader) { this.refresh = reader.GetExchangeInfo(); @@ -150,9 +179,10 @@ public void ReturnReader(ref MessagePackStreamingReader reader) // Clear the reader to prevent accidental reuse by the caller. reader = default; - readerReturned = true; + this.readerReturned = true; } + /// public void ReturnReader(ref MessagePackReader reader) { MessagePackStreamingReader.BufferRefresh refresh = this.Refresh; @@ -162,11 +192,9 @@ public void ReturnReader(ref MessagePackReader reader) // Clear the reader to prevent accidental reuse by the caller. reader = default; - readerReturned = true; + this.readerReturned = true; } - private MessagePackStreamingReader.BufferRefresh Refresh => this.refresh ?? throw new InvalidOperationException($"Call {nameof(this.ReadAsync)} first."); - private void ThrowIfReaderNotReturned() { Verify.Operation(this.readerReturned, "The previous reader must be returned before creating a new one."); diff --git a/src/Nerdbank.MessagePack/MessagePackConverter`1.cs b/src/Nerdbank.MessagePack/MessagePackConverter`1.cs index 7b6353f0..3f36ca42 100644 --- a/src/Nerdbank.MessagePack/MessagePackConverter`1.cs +++ b/src/Nerdbank.MessagePack/MessagePackConverter`1.cs @@ -114,7 +114,7 @@ public virtual ValueTask WriteAsync(MessagePackAsyncWriter writer, T? value, Ser context.CancellationToken.ThrowIfCancellationRequested(); await reader.BufferNextStructureAsync(context); - MessagePackReader syncReader = reader.CreateReader2(); + MessagePackReader syncReader = reader.CreateBufferedReader(); T? result = this.Read(ref syncReader, context); reader.ReturnReader(ref syncReader); return result; diff --git a/src/Nerdbank.MessagePack/MessagePackReader.cs b/src/Nerdbank.MessagePack/MessagePackReader.cs index 913e9e87..b3bd1eda 100644 --- a/src/Nerdbank.MessagePack/MessagePackReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackReader.cs @@ -21,7 +21,9 @@ public ref partial struct MessagePackReader /// /// The reader over the sequence. /// +#pragma warning disable NBMsgPackAsync // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. private MessagePackStreamingReader streamingReader; +#pragma warning restore NBMsgPackAsync // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. /// public MessagePackReader(ReadOnlyMemory msgpack) @@ -244,7 +246,6 @@ public bool TryReadArrayHeader(out int count) default: throw ThrowUnreachable(); } - } /// diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs index faaa5b77..444ecae0 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.cs @@ -8,6 +8,23 @@ namespace Nerdbank.MessagePack; +/// +/// A msgpack decoder that returns error codes rather than throws exceptions +/// when the buffer is incomplete or the token type does not match expectations. +/// +/// +/// All decoding methods on this struct return . +/// Callers must take care to observe this value and take appropriate action. +/// A common calling pattern is to call the decoding method within a loop's expression +/// and use the +/// extension method on the result. +/// The content of the loop should be a call to and to reconstruct +/// the reader using . +/// +/// +/// +/// +[Experimental("NBMsgPackAsync")] public ref partial struct MessagePackStreamingReader { private readonly GetMoreBytesAsync? getMoreBytesAsync; @@ -19,11 +36,26 @@ public ref partial struct MessagePackStreamingReader /// private bool eof; + /// + /// Initializes a new instance of the struct + /// that decodes from a complete buffer. + /// + /// The buffer to decode msgpack from. This buffer should be complete. public MessagePackStreamingReader(scoped in ReadOnlySequence sequence) : this(sequence, null, null) { } + /// + /// Initializes a new instance of the struct + /// that decodes from a buffer that may be initially incomplete. + /// + /// The buffer we have so far. + /// A means to obtain more msgpack bytes when necessary. + /// + /// A value to provide to the delegate. + /// This facilitates reuse of a particular delegate across deserialization operations. + /// public MessagePackStreamingReader(scoped in ReadOnlySequence sequence, GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) { this.reader = new SequenceReader(sequence); @@ -31,6 +63,11 @@ public MessagePackStreamingReader(scoped in ReadOnlySequence sequence, Get this.getMoreBytesState = getMoreBytesState; } + /// + /// Initializes a new instance of the struct + /// that resumes after an operation. + /// + /// The data to reinitialize this ref struct. public MessagePackStreamingReader(scoped in BufferRefresh refresh) : this(refresh.Buffer, refresh.GetMoreBytes, refresh.GetMoreBytesState) { @@ -46,24 +83,51 @@ public MessagePackStreamingReader(scoped in BufferRefresh refresh) /// The position after the last consumed byte (i.e. the last byte from the original buffer that is not expected to be included to the new buffer). /// Any bytes at or following this position that were in the original buffer must be included to the buffer returned from this method. /// + /// + /// The position of the last examined byte. + /// This should be passed to + /// when applicable to ensure that the request to get more bytes is filled with actual more bytes rather than the existing buffer. + /// /// A cancellation token. /// The available buffer, which must contain more bytes than remained after if there are any more bytes to be had. public delegate ValueTask GetMoreBytesAsync(object? state, SequencePosition consumed, SequencePosition examined, CancellationToken cancellationToken); + /// + /// Gets a token that may cancel deserialization. + /// public CancellationToken CancellationToken { get; init; } + /// + /// Gets the reader's position within the current buffer. + /// public SequencePosition Position => this.SequenceReader.Position; + /// + /// Gets the underlying . + /// [UnscopedRef] internal ref SequenceReader SequenceReader => ref this.reader; + /// + /// Gets the error code to return when the buffer has insufficient bytes to finish a decode request. + /// private DecodeResult InsufficientBytes => this.eof ? DecodeResult.EmptyBuffer : DecodeResult.InsufficientBuffer; + /// + /// Peeks at the next msgpack byte without advancing the reader. + /// + /// When successful, receives the next msgpack byte. + /// The success or error code. public DecodeResult TryPeekNextCode(out byte code) { return this.reader.TryPeek(out code) ? DecodeResult.Success : this.InsufficientBytes; } + /// + /// Peeks at the next msgpack token type without advancing the reader. + /// + /// When successful, receives the next msgpack token type. + /// The success or error code. public DecodeResult TryPeekNextMessagePackType(out MessagePackType type) { if (this.reader.TryPeek(out byte code)) @@ -76,6 +140,14 @@ public DecodeResult TryPeekNextMessagePackType(out MessagePackType type) return this.InsufficientBytes; } + /// + /// Reads the next token if it is . + /// + /// + /// if the token was nil and was read, + /// if the token was not nil, + /// or other error codes if the buffer is incomplete. + /// public DecodeResult TryReadNil() { if (this.reader.TryPeek(out byte next)) @@ -94,6 +166,14 @@ public DecodeResult TryReadNil() } } + /// + /// Reads the next token if it is . + /// + /// A value indicating whether the next token was nil. + /// + /// if the next token can be decoded whether or not it was nil, + /// or other error codes if the buffer is incomplete. + /// public DecodeResult TryReadNil(out bool isNil) { DecodeResult result = this.TryReadNil(); @@ -101,6 +181,11 @@ public DecodeResult TryReadNil(out bool isNil) return result == DecodeResult.TokenMismatch ? DecodeResult.Success : result; } + /// + /// Reads a value from the msgpack stream. + /// + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(out bool value) { if (this.reader.TryPeek(out byte next)) @@ -128,6 +213,11 @@ public DecodeResult TryRead(out bool value) } } + /// + /// Reads a value from the msgpack stream. + /// + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(out float value) { DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); @@ -167,6 +257,11 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads a value from the msgpack stream. + /// + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(out double value) { DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); @@ -206,6 +301,11 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads a or value from the msgpack stream. + /// + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(out string? value) { DecodeResult result = this.TryReadNil(); @@ -236,6 +336,11 @@ public DecodeResult TryRead(out string? value) } } + /// + /// Reads a value from the msgpack stream. + /// + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(out DateTime value) { DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, out value, out int tokenSize); @@ -275,6 +380,13 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads a value from the msgpack stream, + /// assuming the given . + /// + /// The extension header that was previously read. + /// The decoded value if the read was successful. + /// The success or error code. public DecodeResult TryRead(ExtensionHeader extensionHeader, out DateTime value) { DecodeResult readResult = MessagePackPrimitives.TryRead(this.reader.UnreadSpan, extensionHeader, out value, out int tokenSize); @@ -314,6 +426,11 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, ExtensionHeade } } + /// + /// Reads an array header from the msgpack stream. + /// + /// The number of elements in the array, if the read was successful. + /// The success or error code. public DecodeResult TryReadArrayHeader(out int count) { DecodeResult readResult = MessagePackPrimitives.TryReadArrayHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); @@ -356,6 +473,11 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads a map header from the msgpack stream. + /// + /// The number of elements in the map, if the read was successful. + /// The success or error code. public DecodeResult TryReadMapHeader(out int count) { DecodeResult readResult = MessagePackPrimitives.TryReadMapHeader(this.reader.UnreadSpan, out uint uintCount, out int tokenSize); @@ -398,6 +520,12 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads a given number of bytes from the msgpack stream without decoding them. + /// + /// The number of bytes to read. + /// The bytes if the read was successful. + /// The success or error code. public DecodeResult TryReadRaw(long length, out ReadOnlySequence rawMsgPack) { if (this.reader.Remaining >= length) @@ -411,6 +539,11 @@ public DecodeResult TryReadRaw(long length, out ReadOnlySequence rawMsgPac return this.InsufficientBytes; } + /// + /// Reads a binary sequence with an appropriate msgpack header from the msgpack stream. + /// + /// The byte sequence if the read was successful. + /// The success or error code. public DecodeResult TryReadBinary(out ReadOnlySequence value) { DecodeResult result = this.TryGetBytesLength(out uint length); @@ -431,6 +564,11 @@ public DecodeResult TryReadBinary(out ReadOnlySequence value) return DecodeResult.Success; } + /// + /// Reads a byte sequence backing a UTF-8 encoded string with an appropriate msgpack header from the msgpack stream. + /// + /// The byte sequence if the read was successful. + /// The success or error code. public DecodeResult TryReadStringSequence(out ReadOnlySequence value) { DecodeResult result = this.TryGetStringLengthInBytes(out uint length); @@ -451,6 +589,13 @@ public DecodeResult TryReadStringSequence(out ReadOnlySequence value) return DecodeResult.Success; } + /// + /// Reads a span backing a UTF-8 encoded string with an appropriate msgpack header from the msgpack stream, + /// if the string is contiguous in memory. + /// + /// Receives a value indicating whether the string was present and contiguous in memory. + /// The span of bytes if the read was successful. + /// The success or error code. public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan value) { SequenceReader oldReader = this.reader; @@ -485,6 +630,11 @@ public DecodeResult TryReadStringSpan(out bool contiguous, out ReadOnlySpan + /// Reads an extension header from the msgpack stream. + /// + /// Receives the extension header if the read was successful. + /// The success or error code. public DecodeResult TryRead(out ExtensionHeader extensionHeader) { DecodeResult readResult = MessagePackPrimitives.TryReadExtensionHeader(this.reader.UnreadSpan, out extensionHeader, out int tokenSize); @@ -525,6 +675,11 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r } } + /// + /// Reads an extension from the msgpack stream. + /// + /// Receives the extension if the read was successful. + /// The success or error code. public DecodeResult TryRead(out Extension extension) { DecodeResult result = this.TryRead(out ExtensionHeader header); @@ -546,6 +701,11 @@ public DecodeResult TryRead(out Extension extension) return DecodeResult.Success; } + /// + /// Advances the reader past the next msgpack structure. + /// + /// The context of the deserialization operation. + /// The success or error code. public DecodeResult TrySkip(SerializationContext context) { DecodeResult result = this.TryPeekNextCode(out byte code); @@ -860,18 +1020,33 @@ private DecodeResult ReadStringSlow(uint byteLength, out string? value) return DecodeResult.Success; } + /// + /// A non- structure that can be used to recreate a after + /// an expression. + /// public struct BufferRefresh { + /// internal CancellationToken CancellationToken { get; init; } + /// + /// Gets the buffer of msgpack already obtained. + /// internal ReadOnlySequence Buffer { get; init; } + /// + /// Gets the delegate that can obtain more bytes. + /// internal GetMoreBytesAsync? GetMoreBytes { get; init; } + /// + /// Gets the state object to supply to the delegate. + /// internal object? GetMoreBytesState { get; init; } + /// + /// Gets a value indicating whether the contains all remaining bytes and will not provide more. + /// internal bool EndOfStream { get; init; } - - public MessagePackStreamingReader CreateReader() => new(this); } } diff --git a/src/Nerdbank.MessagePack/StandardVisitor.cs b/src/Nerdbank.MessagePack/StandardVisitor.cs index f962b3c5..860646c2 100644 --- a/src/Nerdbank.MessagePack/StandardVisitor.cs +++ b/src/Nerdbank.MessagePack/StandardVisitor.cs @@ -280,7 +280,7 @@ internal StandardVisitor(MessagePackSerializer owner, TypeGenerationContext cont }; DeserializePropertyAsync deserializeAsync = async (TDeclaringType container, MessagePackAsyncReader reader, SerializationContext context) => { - MessagePackStreamingReader streamingReader = reader.CreateReader(); + MessagePackStreamingReader streamingReader = reader.CreateStreamingReader(); bool isNil; while (streamingReader.TryReadNil(out isNil).NeedsMoreBytes()) { diff --git a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt index 63c8c243..8131f9b9 100644 --- a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt @@ -85,20 +85,16 @@ Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode.ObjectReference.get -> sbyte Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode.ObjectReference.init -> void Nerdbank.MessagePack.MessagePackAsyncReader -Nerdbank.MessagePack.MessagePackAsyncReader.AdvanceTo(System.SequencePosition consumed) -> void -Nerdbank.MessagePack.MessagePackAsyncReader.AdvanceTo(System.SequencePosition consumed, System.SequencePosition examined) -> void Nerdbank.MessagePack.MessagePackAsyncReader.BufferNextStructureAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.BufferNextStructuresAsync(int minimumDesiredBufferedStructures, int countUpTo, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackAsyncReader.CancellationToken.get -> System.Threading.CancellationToken Nerdbank.MessagePack.MessagePackAsyncReader.CancellationToken.init -> void +Nerdbank.MessagePack.MessagePackAsyncReader.CreateBufferedReader() -> Nerdbank.MessagePack.MessagePackReader +Nerdbank.MessagePack.MessagePackAsyncReader.CreateStreamingReader() -> Nerdbank.MessagePack.MessagePackStreamingReader Nerdbank.MessagePack.MessagePackAsyncReader.MessagePackAsyncReader(System.IO.Pipelines.PipeReader! pipeReader) -> void -Nerdbank.MessagePack.MessagePackAsyncReader.ReadArrayHeaderAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.ReadMapHeaderAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructureAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask> -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructuresAsync(int minimumDesiredBufferedStructures, int countUpTo, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask<(System.Buffers.ReadOnlySequence Buffer, int IncludedStructures)> -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructuresAsync(int minimumDesiredBufferedStructures, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask> -Nerdbank.MessagePack.MessagePackAsyncReader.SkipAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.TryPeekNextMessagePackTypeAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.TryReadNilAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.ReadAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.ReturnReader(ref Nerdbank.MessagePack.MessagePackReader reader) -> void +Nerdbank.MessagePack.MessagePackAsyncReader.ReturnReader(ref Nerdbank.MessagePack.MessagePackStreamingReader reader) -> void Nerdbank.MessagePack.MessagePackAsyncWriter Nerdbank.MessagePack.MessagePackAsyncWriter.CreateWriter() -> Nerdbank.MessagePack.MessagePackWriter Nerdbank.MessagePack.MessagePackAsyncWriter.Flush() -> void @@ -249,6 +245,38 @@ Nerdbank.MessagePack.MessagePackSerializer.SerializeEnumValuesByName.get -> bool Nerdbank.MessagePack.MessagePackSerializer.SerializeEnumValuesByName.init -> void Nerdbank.MessagePack.MessagePackSerializer.StartingContext.get -> Nerdbank.MessagePack.SerializationContext Nerdbank.MessagePack.MessagePackSerializer.StartingContext.init -> void +Nerdbank.MessagePack.MessagePackStreamingReader +Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh +Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh.BufferRefresh() -> void +Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.get -> System.Threading.CancellationToken +Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.init -> void +Nerdbank.MessagePack.MessagePackStreamingReader.GetExchangeInfo() -> Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh +Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader() -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh refresh) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition +Nerdbank.MessagePack.MessagePackStreamingReader.ReplenishBufferAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out bool value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out double value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out float value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.Extension extension) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.ExtensionHeader extensionHeader) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out string? value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadArrayHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadBinary(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadMapHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadNil() -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadNil(out bool isNil) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadRaw(long length, out System.Buffers.ReadOnlySequence rawMsgPack) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadStringSequence(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadStringSpan(out bool contiguous, out System.ReadOnlySpan value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TrySkip(Nerdbank.MessagePack.SerializationContext context) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackType Nerdbank.MessagePack.MessagePackType.Array = 7 -> Nerdbank.MessagePack.MessagePackType Nerdbank.MessagePack.MessagePackType.Binary = 6 -> Nerdbank.MessagePack.MessagePackType diff --git a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt index 7865f95f..7acb420d 100644 --- a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt @@ -81,20 +81,16 @@ Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode.ObjectReference.get -> sbyte Nerdbank.MessagePack.LibraryReservedMessagePackExtensionTypeCode.ObjectReference.init -> void Nerdbank.MessagePack.MessagePackAsyncReader -Nerdbank.MessagePack.MessagePackAsyncReader.AdvanceTo(System.SequencePosition consumed) -> void -Nerdbank.MessagePack.MessagePackAsyncReader.AdvanceTo(System.SequencePosition consumed, System.SequencePosition examined) -> void Nerdbank.MessagePack.MessagePackAsyncReader.BufferNextStructureAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.BufferNextStructuresAsync(int minimumDesiredBufferedStructures, int countUpTo, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackAsyncReader.CancellationToken.get -> System.Threading.CancellationToken Nerdbank.MessagePack.MessagePackAsyncReader.CancellationToken.init -> void +Nerdbank.MessagePack.MessagePackAsyncReader.CreateBufferedReader() -> Nerdbank.MessagePack.MessagePackReader +Nerdbank.MessagePack.MessagePackAsyncReader.CreateStreamingReader() -> Nerdbank.MessagePack.MessagePackStreamingReader Nerdbank.MessagePack.MessagePackAsyncReader.MessagePackAsyncReader(System.IO.Pipelines.PipeReader! pipeReader) -> void -Nerdbank.MessagePack.MessagePackAsyncReader.ReadArrayHeaderAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.ReadMapHeaderAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructureAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask> -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructuresAsync(int minimumDesiredBufferedStructures, int countUpTo, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask<(System.Buffers.ReadOnlySequence Buffer, int IncludedStructures)> -Nerdbank.MessagePack.MessagePackAsyncReader.ReadNextStructuresAsync(int minimumDesiredBufferedStructures, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask> -Nerdbank.MessagePack.MessagePackAsyncReader.SkipAsync(Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.TryPeekNextMessagePackTypeAsync() -> System.Threading.Tasks.ValueTask -Nerdbank.MessagePack.MessagePackAsyncReader.TryReadNilAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.ReadAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackAsyncReader.ReturnReader(ref Nerdbank.MessagePack.MessagePackReader reader) -> void +Nerdbank.MessagePack.MessagePackAsyncReader.ReturnReader(ref Nerdbank.MessagePack.MessagePackStreamingReader reader) -> void Nerdbank.MessagePack.MessagePackAsyncWriter Nerdbank.MessagePack.MessagePackAsyncWriter.CreateWriter() -> Nerdbank.MessagePack.MessagePackWriter Nerdbank.MessagePack.MessagePackAsyncWriter.Flush() -> void @@ -221,6 +217,38 @@ Nerdbank.MessagePack.MessagePackSerializer.SerializeEnumValuesByName.get -> bool Nerdbank.MessagePack.MessagePackSerializer.SerializeEnumValuesByName.init -> void Nerdbank.MessagePack.MessagePackSerializer.StartingContext.get -> Nerdbank.MessagePack.SerializationContext Nerdbank.MessagePack.MessagePackSerializer.StartingContext.init -> void +Nerdbank.MessagePack.MessagePackStreamingReader +Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh +Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh.BufferRefresh() -> void +Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.get -> System.Threading.CancellationToken +Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.init -> void +Nerdbank.MessagePack.MessagePackStreamingReader.GetExchangeInfo() -> Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh +Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader() -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh refresh) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void +Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition +Nerdbank.MessagePack.MessagePackStreamingReader.ReplenishBufferAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out bool value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out double value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out float value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.Extension extension) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.ExtensionHeader extensionHeader) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out string? value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadArrayHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadBinary(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadMapHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadNil() -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadNil(out bool isNil) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadRaw(long length, out System.Buffers.ReadOnlySequence rawMsgPack) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadStringSequence(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryReadStringSpan(out bool contiguous, out System.ReadOnlySpan value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TrySkip(Nerdbank.MessagePack.SerializationContext context) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackType Nerdbank.MessagePack.MessagePackType.Array = 7 -> Nerdbank.MessagePack.MessagePackType Nerdbank.MessagePack.MessagePackType.Binary = 6 -> Nerdbank.MessagePack.MessagePackType diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index fedf858a..e0b4b54d 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -1,6 +1,8 @@ // Copyright (c) Andrew Arnott. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#pragma warning disable NBMsgPackAsync // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + using DecodeResult = Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult; public class MessagePackStreamingReaderTests From a94cf1d21054302198b52fb9143f7db33b5e4445 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 16:29:31 -0700 Subject: [PATCH 17/20] Fix some straggling warnings --- .../MessagePackStreamingReader.Integers.cs | 24 ++++++++++++------- .../MessagePackStreamingReader.Integers.tt | 3 ++- .../net8.0/PublicAPI.Unshipped.txt | 10 ++++++++ .../netstandard2.0/PublicAPI.Unshipped.txt | 10 ++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs index fbec9ccf..a6113ad3 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.cs @@ -21,7 +21,8 @@ public ref partial struct MessagePackStreamingReader /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out Byte value) { @@ -68,7 +69,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out UInt16 value) { @@ -115,7 +117,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out UInt32 value) { @@ -162,7 +165,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out UInt64 value) { @@ -209,7 +213,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out SByte value) { @@ -256,7 +261,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out Int16 value) { @@ -303,7 +309,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out Int32 value) { @@ -350,7 +357,8 @@ static DecodeResult SlowPath(ref MessagePackStreamingReader self, DecodeResult r /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out Int64 value) { diff --git a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt index c270a8b4..9587b533 100644 --- a/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt +++ b/src/Nerdbank.MessagePack/MessagePackStreamingReader.Integers.tt @@ -42,7 +42,8 @@ foreach (var intType in allTypes) { /// Some value between and , /// or any of the other MsgPack integer types. /// - /// The value. + /// Receives the decoded value. + /// The success or error code. /// Thrown when the value exceeds what can be stored in the returned type. public DecodeResult TryRead(out <#=intType.Name#> value) { diff --git a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt index 8131f9b9..9a8708a0 100644 --- a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt @@ -45,6 +45,7 @@ const Nerdbank.MessagePack.MessagePackCode.UInt64 = 207 -> byte const Nerdbank.MessagePack.MessagePackCode.UInt8 = 204 -> byte const Nerdbank.MessagePack.ReservedMessagePackExtensionTypeCode.DateTime = -1 -> sbyte Nerdbank.MessagePack.ByValueEqualityComparer +Nerdbank.MessagePack.DecodeResultExtensions Nerdbank.MessagePack.Extension Nerdbank.MessagePack.Extension.Data.get -> System.Buffers.ReadOnlySequence Nerdbank.MessagePack.Extension.Data.set -> void @@ -262,12 +263,20 @@ Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) - Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out bool value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out byte value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out double value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out float value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out int value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out long value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.Extension extension) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.ExtensionHeader extensionHeader) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out sbyte value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out short value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out string? value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out uint value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out ulong value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out ushort value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadArrayHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadBinary(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadMapHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult @@ -370,6 +379,7 @@ static Nerdbank.MessagePack.ByValueEqualityComparer.GetHashResistant() -> System.Collections.Generic.IEqualityComparer! static Nerdbank.MessagePack.ByValueEqualityComparer.GetHashResistant(PolyType.Abstractions.ITypeShape! shape) -> System.Collections.Generic.IEqualityComparer! static Nerdbank.MessagePack.ByValueEqualityComparer.GetHashResistant(PolyType.ITypeShapeProvider! provider) -> System.Collections.Generic.IEqualityComparer! +static Nerdbank.MessagePack.DecodeResultExtensions.NeedsMoreBytes(this Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult result) -> bool static Nerdbank.MessagePack.MessagePackCode.ToFormatName(byte code) -> string! static Nerdbank.MessagePack.MessagePackCode.ToMessagePackType(byte code) -> Nerdbank.MessagePack.MessagePackType static Nerdbank.MessagePack.MessagePackConverter.ApplyJsonSchemaNullability(System.Text.Json.Nodes.JsonObject! schema) -> System.Text.Json.Nodes.JsonObject! diff --git a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt index 7acb420d..7d7c5bd2 100644 --- a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt @@ -45,6 +45,7 @@ const Nerdbank.MessagePack.MessagePackCode.UInt64 = 207 -> byte const Nerdbank.MessagePack.MessagePackCode.UInt8 = 204 -> byte const Nerdbank.MessagePack.ReservedMessagePackExtensionTypeCode.DateTime = -1 -> sbyte Nerdbank.MessagePack.ByValueEqualityComparer +Nerdbank.MessagePack.DecodeResultExtensions Nerdbank.MessagePack.Extension Nerdbank.MessagePack.Extension.Data.get -> System.Buffers.ReadOnlySequence Nerdbank.MessagePack.Extension.Data.set -> void @@ -234,12 +235,20 @@ Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) - Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out bool value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out byte value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out double value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out float value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out int value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out long value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.Extension extension) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out Nerdbank.MessagePack.ExtensionHeader extensionHeader) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out sbyte value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out short value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out string? value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out uint value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out ulong value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult +Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(out ushort value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadArrayHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadBinary(out System.Buffers.ReadOnlySequence value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryReadMapHeader(out int count) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult @@ -335,6 +344,7 @@ static Nerdbank.MessagePack.ByValueEqualityComparer.GetDefault(PolyType.Abstr static Nerdbank.MessagePack.ByValueEqualityComparer.GetDefault(PolyType.ITypeShapeProvider! provider) -> System.Collections.Generic.IEqualityComparer! static Nerdbank.MessagePack.ByValueEqualityComparer.GetHashResistant(PolyType.Abstractions.ITypeShape! shape) -> System.Collections.Generic.IEqualityComparer! static Nerdbank.MessagePack.ByValueEqualityComparer.GetHashResistant(PolyType.ITypeShapeProvider! provider) -> System.Collections.Generic.IEqualityComparer! +static Nerdbank.MessagePack.DecodeResultExtensions.NeedsMoreBytes(this Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult result) -> bool static Nerdbank.MessagePack.MessagePackCode.ToFormatName(byte code) -> string! static Nerdbank.MessagePack.MessagePackCode.ToMessagePackType(byte code) -> Nerdbank.MessagePack.MessagePackType static Nerdbank.MessagePack.MessagePackConverter.ApplyJsonSchemaNullability(System.Text.Json.Nodes.JsonObject! schema) -> System.Text.Json.Nodes.JsonObject! From 3135aa45741a6bb4bf020d28e152a75c8d4f68a1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 17:12:30 -0700 Subject: [PATCH 18/20] Touch up on API name --- samples/CustomConverters.cs | 16 ++++++++-------- .../Converters/ArrayConverter`1.cs | 4 ++-- .../Converters/DictionaryConverter`3.cs | 4 ++-- .../Converters/EnumerableConverter`2.cs | 2 +- .../Converters/ObjectArrayConverter`1.cs | 8 ++++---- .../ObjectArrayWithNonDefaultCtorConverter`2.cs | 8 ++++---- .../Converters/ObjectMapConverter`1.cs | 6 +++--- .../ObjectMapWithNonDefaultCtorConverter`2.cs | 6 +++--- .../MessagePackAsyncReader.cs | 2 +- .../MessagePackStreamingReader.cs | 7 +++++-- src/Nerdbank.MessagePack/StandardVisitor.cs | 2 +- .../net8.0/PublicAPI.Unshipped.txt | 4 ++-- .../netstandard2.0/PublicAPI.Unshipped.txt | 4 ++-- .../MessagePackStreamingReaderTests.cs | 6 +++--- 14 files changed, 41 insertions(+), 38 deletions(-) diff --git a/samples/CustomConverters.cs b/samples/CustomConverters.cs index ed57a789..fd12a648 100644 --- a/samples/CustomConverters.cs +++ b/samples/CustomConverters.cs @@ -177,7 +177,7 @@ public override void Write(ref MessagePackWriter writer, in Foo? value, Serializ #endregion #else -#region DelegateSubValuesNETFX + #region DelegateSubValuesNETFX public override void Write(ref MessagePackWriter writer, in Foo? value, SerializationContext context) { if (value is null) @@ -195,7 +195,7 @@ public override void Write(ref MessagePackWriter writer, in Foo? value, Serializ writer.Write("MyProperty2"); writer.Write(value.MyProperty2); } -#endregion + #endregion #endif } } @@ -230,7 +230,7 @@ public override void Write(ref MessagePackWriter writer, in Foo? value, Serializ } } #else -#region WitnessOnFormatterNETFX + #region WitnessOnFormatterNETFX // SomeOtherType is outside your assembly and not attributed. public partial record SomeOtherType; @@ -242,7 +242,7 @@ partial class FooConverter : MessagePackConverter // ... context.GetConverter(ShapeProvider).Read(ref reader, context); // ... -#endregion + #endregion throw new NotImplementedException(); } @@ -276,7 +276,7 @@ partial class FooConverter : MessagePackConverter // ... #endregion #else -#region ArrayWitnessOnFormatterNETFX + #region ArrayWitnessOnFormatterNETFX // SomeOtherType is outside your assembly and not attributed. public partial record SomeOtherType; @@ -288,7 +288,7 @@ partial class FooConverter : MessagePackConverter // ... context.GetConverter(ShapeProvider).Read(ref reader, context); // ... -#endregion + #endregion #endif throw new NotImplementedException(); } @@ -358,7 +358,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } #endregion @@ -366,7 +366,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, { while (streamingReader.TrySkip(context).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } } diff --git a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs index 7d6254f0..3bbdbb66 100644 --- a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs @@ -99,7 +99,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } if (success) @@ -114,7 +114,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs index 0887fd37..96f8d2ad 100644 --- a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs +++ b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs @@ -144,7 +144,7 @@ internal class MutableDictionaryConverter( bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } reader.ReturnReader(ref streamingReader); @@ -182,7 +182,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TDict int count; while (streamingReader.TryReadMapHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs index 539c7b47..9cb2938a 100644 --- a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs @@ -143,7 +143,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TEnum int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } for (int i = 0; i < count; i++) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs index 1e0ac6fb..71cf4b22 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs @@ -335,7 +335,7 @@ int NextSyncBatchSize() bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } if (success) @@ -354,7 +354,7 @@ int NextSyncBatchSize() MessagePackType peekType; while (streamingReader.TryPeekNextMessagePackType(out peekType).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } if (peekType == MessagePackType.Map) @@ -362,7 +362,7 @@ int NextSyncBatchSize() int mapEntries; while (streamingReader.TryReadMapHeader(out mapEntries).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } // We're going to read in bursts. Anything we happen to get in one buffer, we'll read synchronously regardless of whether the property is async. @@ -426,7 +426,7 @@ int NextSyncBatchSize() int arrayLength; while (streamingReader.TryReadArrayHeader(out arrayLength).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs index 36f487d1..92b6d406 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs @@ -85,7 +85,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter loop's expression /// and use the /// extension method on the result. -/// The content of the loop should be a call to and to reconstruct +/// The content of the loop should be a call to and to reconstruct /// the reader using . /// /// +/// +/// The following snippet demonstrates a common pattern for properly reading with this type. +/// /// /// [Experimental("NBMsgPackAsync")] @@ -848,7 +851,7 @@ DecodeResult TrySkip(ref MessagePackStreamingReader self, int count, Serializati /// It must not be used after calling this method. /// Instead, the result can use the result of this method to recreate a new value. /// - public ValueTask ReplenishBufferAsync() + public ValueTask ReadMoreBytes() { if (this.getMoreBytesAsync is null || this.eof) { diff --git a/src/Nerdbank.MessagePack/StandardVisitor.cs b/src/Nerdbank.MessagePack/StandardVisitor.cs index 860646c2..e96ca9f7 100644 --- a/src/Nerdbank.MessagePack/StandardVisitor.cs +++ b/src/Nerdbank.MessagePack/StandardVisitor.cs @@ -284,7 +284,7 @@ internal StandardVisitor(MessagePackSerializer owner, TypeGenerationContext cont bool isNil; while (streamingReader.TryReadNil(out isNil).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReplenishBufferAsync()); + streamingReader = new(await streamingReader.ReadMoreBytes()); } if (!isNil) diff --git a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt index 9a8708a0..1f492718 100644 --- a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt @@ -258,7 +258,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReplenishBufferAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytes() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult @@ -453,4 +453,4 @@ virtual Nerdbank.MessagePack.KnownSubTypeAttribute.Shape.get -> PolyType.Abstrac virtual Nerdbank.MessagePack.MessagePackConverter.GetJsonSchema(Nerdbank.MessagePack.JsonSchemaContext! context, PolyType.Abstractions.ITypeShape! typeShape) -> System.Text.Json.Nodes.JsonObject? virtual Nerdbank.MessagePack.MessagePackConverter.PreferAsyncSerialization.get -> bool virtual Nerdbank.MessagePack.MessagePackConverter.ReadAsync(Nerdbank.MessagePack.MessagePackAsyncReader! reader, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask -virtual Nerdbank.MessagePack.MessagePackConverter.WriteAsync(Nerdbank.MessagePack.MessagePackAsyncWriter! writer, T? value, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask \ No newline at end of file +virtual Nerdbank.MessagePack.MessagePackConverter.WriteAsync(Nerdbank.MessagePack.MessagePackAsyncWriter! writer, T? value, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask diff --git a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt index 7d7c5bd2..61bba0ef 100644 --- a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt @@ -230,7 +230,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReplenishBufferAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytes() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult @@ -418,4 +418,4 @@ virtual Nerdbank.MessagePack.KnownSubTypeAttribute.Shape.get -> PolyType.Abstrac virtual Nerdbank.MessagePack.MessagePackConverter.GetJsonSchema(Nerdbank.MessagePack.JsonSchemaContext! context, PolyType.Abstractions.ITypeShape! typeShape) -> System.Text.Json.Nodes.JsonObject? virtual Nerdbank.MessagePack.MessagePackConverter.PreferAsyncSerialization.get -> bool virtual Nerdbank.MessagePack.MessagePackConverter.ReadAsync(Nerdbank.MessagePack.MessagePackAsyncReader! reader, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask -virtual Nerdbank.MessagePack.MessagePackConverter.WriteAsync(Nerdbank.MessagePack.MessagePackAsyncWriter! writer, T? value, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask \ No newline at end of file +virtual Nerdbank.MessagePack.MessagePackConverter.WriteAsync(Nerdbank.MessagePack.MessagePackAsyncWriter! writer, T? value, Nerdbank.MessagePack.SerializationContext context) -> System.Threading.Tasks.ValueTask diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index e0b4b54d..93193329 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -34,7 +34,7 @@ public async Task ReplenishBufferAsync_AddsMoreBytesOnce() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + incompleteReader = new(await incompleteReader.ReadMoreBytes()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); @@ -58,14 +58,14 @@ public async Task ReplenishBufferAsync_AddsMoreBytes_ThenCompletes() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + incompleteReader = new(await incompleteReader.ReadMoreBytes()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadNil()); - incompleteReader = new(await incompleteReader.ReplenishBufferAsync()); + incompleteReader = new(await incompleteReader.ReadMoreBytes()); Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); } From 3a6a1048d14adc78c3e27f7130a86cd8afdaccaa Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 17:13:59 -0700 Subject: [PATCH 19/20] Fix async suffix --- samples/CustomConverters.cs | 4 ++-- src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs | 4 ++-- .../Converters/DictionaryConverter`3.cs | 4 ++-- .../Converters/EnumerableConverter`2.cs | 2 +- .../Converters/ObjectArrayConverter`1.cs | 8 ++++---- .../ObjectArrayWithNonDefaultCtorConverter`2.cs | 8 ++++---- .../Converters/ObjectMapConverter`1.cs | 6 +++--- .../Converters/ObjectMapWithNonDefaultCtorConverter`2.cs | 6 +++--- src/Nerdbank.MessagePack/MessagePackAsyncReader.cs | 2 +- src/Nerdbank.MessagePack/MessagePackStreamingReader.cs | 4 ++-- src/Nerdbank.MessagePack/StandardVisitor.cs | 2 +- src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt | 2 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 2 +- .../MessagePackStreamingReaderTests.cs | 6 +++--- 14 files changed, 30 insertions(+), 30 deletions(-) diff --git a/samples/CustomConverters.cs b/samples/CustomConverters.cs index fd12a648..13db7f78 100644 --- a/samples/CustomConverters.cs +++ b/samples/CustomConverters.cs @@ -358,7 +358,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } #endregion @@ -366,7 +366,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, { while (streamingReader.TrySkip(context).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } } diff --git a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs index 3bbdbb66..1b86d954 100644 --- a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs @@ -99,7 +99,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } if (success) @@ -114,7 +114,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs index 96f8d2ad..76e8243d 100644 --- a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs +++ b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs @@ -144,7 +144,7 @@ internal class MutableDictionaryConverter( bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); @@ -182,7 +182,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TDict int count; while (streamingReader.TryReadMapHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs index 9cb2938a..8fc8b83f 100644 --- a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs @@ -143,7 +143,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TEnum int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } for (int i = 0; i < count; i++) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs index 71cf4b22..0d234455 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs @@ -335,7 +335,7 @@ int NextSyncBatchSize() bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } if (success) @@ -354,7 +354,7 @@ int NextSyncBatchSize() MessagePackType peekType; while (streamingReader.TryPeekNextMessagePackType(out peekType).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } if (peekType == MessagePackType.Map) @@ -362,7 +362,7 @@ int NextSyncBatchSize() int mapEntries; while (streamingReader.TryReadMapHeader(out mapEntries).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } // We're going to read in bursts. Anything we happen to get in one buffer, we'll read synchronously regardless of whether the property is async. @@ -426,7 +426,7 @@ int NextSyncBatchSize() int arrayLength; while (streamingReader.TryReadArrayHeader(out arrayLength).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs index 92b6d406..2e8d5787 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs @@ -85,7 +85,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter loop's expression /// and use the /// extension method on the result. -/// The content of the loop should be a call to and to reconstruct +/// The content of the loop should be a call to and to reconstruct /// the reader using . /// /// @@ -851,7 +851,7 @@ DecodeResult TrySkip(ref MessagePackStreamingReader self, int count, Serializati /// It must not be used after calling this method. /// Instead, the result can use the result of this method to recreate a new value. /// - public ValueTask ReadMoreBytes() + public ValueTask ReadMoreBytesAsync() { if (this.getMoreBytesAsync is null || this.eof) { diff --git a/src/Nerdbank.MessagePack/StandardVisitor.cs b/src/Nerdbank.MessagePack/StandardVisitor.cs index e96ca9f7..a11d1d55 100644 --- a/src/Nerdbank.MessagePack/StandardVisitor.cs +++ b/src/Nerdbank.MessagePack/StandardVisitor.cs @@ -284,7 +284,7 @@ internal StandardVisitor(MessagePackSerializer owner, TypeGenerationContext cont bool isNil; while (streamingReader.TryReadNil(out isNil).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytes()); + streamingReader = new(await streamingReader.ReadMoreBytesAsync()); } if (!isNil) diff --git a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt index 1f492718..0cb52ec1 100644 --- a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt @@ -258,7 +258,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytes() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytesAsync() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult diff --git a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt index 61bba0ef..273f43fd 100644 --- a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt @@ -230,7 +230,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytes() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytesAsync() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index 93193329..1e17a930 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -34,7 +34,7 @@ public async Task ReplenishBufferAsync_AddsMoreBytesOnce() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReadMoreBytes()); + incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); @@ -58,14 +58,14 @@ public async Task ReplenishBufferAsync_AddsMoreBytes_ThenCompletes() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReadMoreBytes()); + incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadNil()); - incompleteReader = new(await incompleteReader.ReadMoreBytes()); + incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); } From 1119829f3b6c2f3214729052ebbdf751bd77f877 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 Dec 2024 17:16:47 -0700 Subject: [PATCH 20/20] Use Fetch instead of Read --- samples/CustomConverters.cs | 4 ++-- src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs | 4 ++-- .../Converters/DictionaryConverter`3.cs | 4 ++-- .../Converters/EnumerableConverter`2.cs | 2 +- .../Converters/ObjectArrayConverter`1.cs | 8 ++++---- .../ObjectArrayWithNonDefaultCtorConverter`2.cs | 8 ++++---- .../Converters/ObjectMapConverter`1.cs | 6 +++--- .../Converters/ObjectMapWithNonDefaultCtorConverter`2.cs | 6 +++--- src/Nerdbank.MessagePack/MessagePackAsyncReader.cs | 2 +- src/Nerdbank.MessagePack/MessagePackStreamingReader.cs | 4 ++-- src/Nerdbank.MessagePack/StandardVisitor.cs | 2 +- src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt | 2 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 2 +- .../MessagePackStreamingReaderTests.cs | 6 +++--- 14 files changed, 30 insertions(+), 30 deletions(-) diff --git a/samples/CustomConverters.cs b/samples/CustomConverters.cs index 13db7f78..2bbbd458 100644 --- a/samples/CustomConverters.cs +++ b/samples/CustomConverters.cs @@ -358,7 +358,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } #endregion @@ -366,7 +366,7 @@ public override void Write(ref MessagePackWriter writer, in MyCustomType? value, { while (streamingReader.TrySkip(context).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } } diff --git a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs index 1b86d954..4b155bf3 100644 --- a/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ArrayConverter`1.cs @@ -99,7 +99,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } if (success) @@ -114,7 +114,7 @@ public override async ValueTask WriteAsync(MessagePackAsyncWriter writer, TEleme int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs index 76e8243d..076a8ec4 100644 --- a/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs +++ b/src/Nerdbank.MessagePack/Converters/DictionaryConverter`3.cs @@ -144,7 +144,7 @@ internal class MutableDictionaryConverter( bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); @@ -182,7 +182,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TDict int count; while (streamingReader.TryReadMapHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs index 8fc8b83f..051900b2 100644 --- a/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/EnumerableConverter`2.cs @@ -143,7 +143,7 @@ public async ValueTask DeserializeIntoAsync(MessagePackAsyncReader reader, TEnum int count; while (streamingReader.TryReadArrayHeader(out count).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } for (int i = 0; i < count; i++) diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs index 0d234455..e787a03c 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayConverter`1.cs @@ -335,7 +335,7 @@ int NextSyncBatchSize() bool success; while (streamingReader.TryReadNil(out success).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } if (success) @@ -354,7 +354,7 @@ int NextSyncBatchSize() MessagePackType peekType; while (streamingReader.TryPeekNextMessagePackType(out peekType).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } if (peekType == MessagePackType.Map) @@ -362,7 +362,7 @@ int NextSyncBatchSize() int mapEntries; while (streamingReader.TryReadMapHeader(out mapEntries).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } // We're going to read in bursts. Anything we happen to get in one buffer, we'll read synchronously regardless of whether the property is async. @@ -426,7 +426,7 @@ int NextSyncBatchSize() int arrayLength; while (streamingReader.TryReadArrayHeader(out arrayLength).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } reader.ReturnReader(ref streamingReader); diff --git a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs index 2e8d5787..5e2f5e96 100644 --- a/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs +++ b/src/Nerdbank.MessagePack/Converters/ObjectArrayWithNonDefaultCtorConverter`2.cs @@ -85,7 +85,7 @@ internal class ObjectArrayWithNonDefaultCtorConverter loop's expression /// and use the /// extension method on the result. -/// The content of the loop should be a call to and to reconstruct +/// The content of the loop should be a call to and to reconstruct /// the reader using . /// /// @@ -851,7 +851,7 @@ DecodeResult TrySkip(ref MessagePackStreamingReader self, int count, Serializati /// It must not be used after calling this method. /// Instead, the result can use the result of this method to recreate a new value. /// - public ValueTask ReadMoreBytesAsync() + public ValueTask FetchMoreBytesAsync() { if (this.getMoreBytesAsync is null || this.eof) { diff --git a/src/Nerdbank.MessagePack/StandardVisitor.cs b/src/Nerdbank.MessagePack/StandardVisitor.cs index a11d1d55..0eda4377 100644 --- a/src/Nerdbank.MessagePack/StandardVisitor.cs +++ b/src/Nerdbank.MessagePack/StandardVisitor.cs @@ -284,7 +284,7 @@ internal StandardVisitor(MessagePackSerializer owner, TypeGenerationContext cont bool isNil; while (streamingReader.TryReadNil(out isNil).NeedsMoreBytes()) { - streamingReader = new(await streamingReader.ReadMoreBytesAsync()); + streamingReader = new(await streamingReader.FetchMoreBytesAsync()); } if (!isNil) diff --git a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt index 0cb52ec1..7fc8e3a3 100644 --- a/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/net8.0/PublicAPI.Unshipped.txt @@ -251,6 +251,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh.BufferRefresh() -> void Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.get -> System.Threading.CancellationToken Nerdbank.MessagePack.MessagePackStreamingReader.CancellationToken.init -> void +Nerdbank.MessagePack.MessagePackStreamingReader.FetchMoreBytesAsync() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.GetExchangeInfo() -> Nerdbank.MessagePack.MessagePackStreamingReader.BufferRefresh Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader() -> void @@ -258,7 +259,6 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytesAsync() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult diff --git a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt index 273f43fd..222ac607 100644 --- a/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/Nerdbank.MessagePack/netstandard2.0/PublicAPI.Unshipped.txt @@ -230,7 +230,7 @@ Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scope Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence) -> void Nerdbank.MessagePack.MessagePackStreamingReader.MessagePackStreamingReader(scoped in System.Buffers.ReadOnlySequence sequence, Nerdbank.MessagePack.MessagePackStreamingReader.GetMoreBytesAsync? additionalBytesSource, object? getMoreBytesState) -> void Nerdbank.MessagePack.MessagePackStreamingReader.Position.get -> System.SequencePosition -Nerdbank.MessagePack.MessagePackStreamingReader.ReadMoreBytesAsync() -> System.Threading.Tasks.ValueTask +Nerdbank.MessagePack.MessagePackStreamingReader.FetchMoreBytesAsync() -> System.Threading.Tasks.ValueTask Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextCode(out byte code) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryPeekNextMessagePackType(out Nerdbank.MessagePack.MessagePackType type) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult Nerdbank.MessagePack.MessagePackStreamingReader.TryRead(Nerdbank.MessagePack.ExtensionHeader extensionHeader, out System.DateTime value) -> Nerdbank.MessagePack.MessagePackPrimitives.DecodeResult diff --git a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs index 1e17a930..3f6766f0 100644 --- a/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs +++ b/test/Nerdbank.MessagePack.Tests/MessagePackStreamingReaderTests.cs @@ -34,7 +34,7 @@ public async Task ReplenishBufferAsync_AddsMoreBytesOnce() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); + incompleteReader = new(await incompleteReader.FetchMoreBytesAsync()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); @@ -58,14 +58,14 @@ public async Task ReplenishBufferAsync_AddsMoreBytes_ThenCompletes() Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out bool boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryRead(out boolean)); - incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); + incompleteReader = new(await incompleteReader.FetchMoreBytesAsync()); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.True(boolean); Assert.Equal(DecodeResult.Success, incompleteReader.TryRead(out boolean)); Assert.False(boolean); Assert.Equal(DecodeResult.InsufficientBuffer, incompleteReader.TryReadNil()); - incompleteReader = new(await incompleteReader.ReadMoreBytesAsync()); + incompleteReader = new(await incompleteReader.FetchMoreBytesAsync()); Assert.Equal(DecodeResult.EmptyBuffer, incompleteReader.TryReadNil()); }