private static void HandleEndObject(ref DdbReadStack state) { if (state.IsLastFrame) { return; } var document = state.GetCurrent().CreateDocumentFromBuffer(); state.PopObject(); if (document == null) { return; } ref var current = ref state.GetCurrent();
public static async ValueTask <ReadResult <Document> > ReadAsync(Stream utf8Json, IParsingOptions options, bool returnCrc, CancellationToken cancellationToken = default) { var readerState = new JsonReaderState(); var readStack = new DdbReadStack(DdbReadStack.DefaultStackLength, options.Metadata); try { options.StartParsing(ref readStack); var buffer = ArrayPool <byte> .Shared.Rent(DefaultBufferSize); var clearMax = 0; try { var bytesInBuffer = 0; uint crc = 0; while (true) { var isFinalBlock = false; while (true) { var bytesRead = await utf8Json.ReadAsync(new Memory <byte>(buffer, bytesInBuffer, buffer.Length - bytesInBuffer), cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { isFinalBlock = true; break; } if (returnCrc) { crc = Crc32Algorithm.Append(crc, buffer, bytesInBuffer, bytesRead); } bytesInBuffer += bytesRead; if (bytesInBuffer == buffer.Length) { break; } } if (bytesInBuffer > clearMax) { clearMax = bytesInBuffer; } ReadCore(ref readerState, isFinalBlock, new ReadOnlySpan <byte>(buffer, 0, bytesInBuffer), ref readStack, options); var bytesConsumed = (int)readStack.BytesConsumed; bytesInBuffer -= bytesConsumed; if (isFinalBlock) { break; } // Check if we need to shift or expand the buffer because there wasn't enough data to complete deserialization. if ((uint)bytesInBuffer > ((uint)buffer.Length / 2)) { // We have less than half the buffer available, double the buffer size. byte[] dest = ArrayPool <byte> .Shared.Rent((buffer.Length < (int.MaxValue / 2))?buffer.Length * 2 : int.MaxValue); // Copy the unprocessed data to the new buffer while shifting the processed bytes. Buffer.BlockCopy(buffer, bytesConsumed, dest, 0, bytesInBuffer); new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); clearMax = bytesInBuffer; buffer = dest; } else if (bytesInBuffer != 0) { // Shift the processed bytes to the beginning of buffer to make more room. Buffer.BlockCopy(buffer, bytesConsumed, buffer, 0, bytesInBuffer); } } return(new ReadResult <Document>(readStack.GetCurrent().CreateDocumentFromBuffer(), crc)); } finally { new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); } } finally { readStack.Dispose(); } }
private static void ReadCore(ref Utf8JsonReader reader, ref DdbReadStack state, IParsingOptions options) { while (reader.Read()) { switch (reader.TokenType) { case JsonTokenType.String: { HandleStringValue(ref reader, ref state); break; } case JsonTokenType.PropertyName: { HandlePropertyName(ref reader, ref state); break; } case JsonTokenType.StartObject: { if (!state.IsLastFrame || state.GetCurrent().IsProcessingValue()) { // Parse inner object start HandleNestedStartObject(ref state); } break; } case JsonTokenType.EndObject: { HandleEndObject(ref state); break; } case JsonTokenType.True: { HandleBoolValue(ref state, true); break; } case JsonTokenType.False: { HandleBoolValue(ref state, false); break; } case JsonTokenType.StartArray: { HandleStartArray(ref state); break; } case JsonTokenType.EndArray: { HandleEndArray(ref state); break; } case JsonTokenType.Number: { HandleNumberValue(ref reader, ref state, options); break; } case JsonTokenType.Null: { HandleNullValue(ref state); break; } } } state.BytesConsumed += reader.BytesConsumed; }