diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs index 0ad286f378..5e72525fc9 100644 --- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs @@ -161,12 +161,21 @@ namespace Google.Protobuf private static void AssertReadFromParseContext(ReadOnlySequence input, ParseContextAssertAction assertAction, bool assertIsAtEnd) { + // Check as ReadOnlySequence ParseContext.Initialize(input, out ParseContext parseCtx); assertAction(ref parseCtx); if (assertIsAtEnd) { Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state)); } + + // Check as ReadOnlySpan + ParseContext.Initialize(input.ToArray().AsSpan(), out ParseContext spanParseContext); + assertAction(ref spanParseContext); + if (assertIsAtEnd) + { + Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref spanParseContext.buffer, ref spanParseContext.state)); + } } [Test] diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs index b09f96ce28..27b23c0d9c 100644 --- a/csharp/src/Google.Protobuf/CodedInputStream.cs +++ b/csharp/src/Google.Protobuf/CodedInputStream.cs @@ -435,8 +435,7 @@ namespace Google.Protobuf // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to // invoke the legacy MergeFrom(CodedInputStream) method. // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). - var span = new ReadOnlySpan(buffer); - ParseContext.Initialize(ref span, ref state, out ParseContext ctx); + ParseContext.Initialize(buffer.AsSpan(), ref state, out ParseContext ctx); try { ParsingPrimitivesMessages.ReadMessage(ref ctx, builder); diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs index d43177c0a3..c4b3f82343 100644 --- a/csharp/src/Google.Protobuf/MessageExtensions.cs +++ b/csharp/src/Google.Protobuf/MessageExtensions.cs @@ -86,7 +86,7 @@ namespace Google.Protobuf /// Span containing the data to merge, which must be protobuf-encoded binary data. [SecuritySafeCritical] public static void MergeFrom(this IMessage message, ReadOnlySpan span) => - MergeFrom(message, ref span, false, null); + MergeFrom(message, span, false, null); /// /// Merges length-delimited data from the given stream into an existing message. @@ -304,9 +304,9 @@ namespace Google.Protobuf } [SecuritySafeCritical] - internal static void MergeFrom(this IMessage message, ref ReadOnlySpan data, bool discardUnknownFields, ExtensionRegistry registry) + internal static void MergeFrom(this IMessage message, ReadOnlySpan data, bool discardUnknownFields, ExtensionRegistry registry) { - ParseContext.Initialize(ref data, out ParseContext ctx); + ParseContext.Initialize(data, out ParseContext ctx); ctx.DiscardUnknownFields = discardUnknownFields; ctx.ExtensionRegistry = registry; ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message); diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs index 74ef50308d..30a25a8698 100644 --- a/csharp/src/Google.Protobuf/MessageParser.cs +++ b/csharp/src/Google.Protobuf/MessageParser.cs @@ -137,7 +137,7 @@ namespace Google.Protobuf public IMessage ParseFrom(ReadOnlySpan data) { IMessage message = factory(); - message.MergeFrom(ref data, DiscardUnknownFields, Extensions); + message.MergeFrom(data, DiscardUnknownFields, Extensions); return message; } @@ -337,7 +337,7 @@ namespace Google.Protobuf public new T ParseFrom(ReadOnlySpan data) { T message = factory(); - message.MergeFrom(ref data, DiscardUnknownFields, Extensions); + message.MergeFrom(data, DiscardUnknownFields, Extensions); return message; } diff --git a/csharp/src/Google.Protobuf/ParseContext.cs b/csharp/src/Google.Protobuf/ParseContext.cs index 5bee01b339..7b278b5a92 100644 --- a/csharp/src/Google.Protobuf/ParseContext.cs +++ b/csharp/src/Google.Protobuf/ParseContext.cs @@ -58,34 +58,30 @@ namespace Google.Protobuf internal ReadOnlySpan buffer; internal ParserInternalState state; + /// + /// Initialize a , building all from defaults and + /// the given . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Initialize(ref ReadOnlySpan buffer, ref ParserInternalState state, out ParseContext ctx) + internal static void Initialize(ReadOnlySpan buffer, out ParseContext ctx) { - ctx.buffer = buffer; - ctx.state = state; - } + ParserInternalState state = default; + state.sizeLimit = DefaultSizeLimit; + state.recursionLimit = DefaultRecursionLimit; + state.currentLimit = int.MaxValue; + state.bufferSize = buffer.Length; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Initialize(ref ReadOnlySpan input, out ParseContext ctx) - { - Initialize(ref input, DefaultRecursionLimit, out ctx); + Initialize(buffer, ref state, out ctx); } + /// + /// Initialize a using existing , e.g. from . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Initialize(ref ReadOnlySpan input, int recursionLimit, out ParseContext ctx) + internal static void Initialize(ReadOnlySpan buffer, ref ParserInternalState state, out ParseContext ctx) { - ctx.buffer = input; - ctx.state = default; - ctx.state.lastTag = 0; - ctx.state.recursionDepth = 0; - ctx.state.sizeLimit = DefaultSizeLimit; - ctx.state.recursionLimit = recursionLimit; - ctx.state.currentLimit = int.MaxValue; - ctx.state.bufferPos = 0; - ctx.state.bufferSize = input.Length; - - ctx.state.DiscardUnknownFields = false; - ctx.state.ExtensionRegistry = null; + ctx.buffer = buffer; + ctx.state = state; } ///