Beispiel #1
0
        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();
Beispiel #2
0
        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;
        }