< Summary

Information
Class: System.Text.Json.Serialization.Converters.IAsyncEnumerableOfTConverter<T1, T2>
Assembly: System.Text.Json
File(s): C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Converters\Collection\IAsyncEnumerableOfTConverter.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 75
Coverable lines: 75
Total lines: 150
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 22
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
OnTryRead(...)0%220%
Add(TElement& modreq(...)100%110%
CreateCollection(...)100%110%
OnTryWrite(...)0%220%
OnWriteResume(...)0%16160%
.ctor()100%110%
GetAsyncEnumerator()0%220%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Converters\Collection\IAsyncEnumerableOfTConverter.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using System.Diagnostics;
 6using System.Threading;
 7using System.Threading.Tasks;
 8
 9namespace System.Text.Json.Serialization.Converters
 10{
 11    internal sealed class IAsyncEnumerableOfTConverter<TAsyncEnumerable, TElement>
 12        : JsonCollectionConverter<TAsyncEnumerable, TElement>
 13        where TAsyncEnumerable : IAsyncEnumerable<TElement>
 14    {
 15        internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, s
 016        {
 017            if (!typeToConvert.IsAssignableFrom(typeof(IAsyncEnumerable<TElement>)))
 018            {
 019                ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(Type, ref reader, ref state);
 20            }
 21
 022            return base.OnTryRead(ref reader, typeToConvert, options, ref state, out value!);
 023        }
 24
 25        protected override void Add(in TElement value, ref ReadStack state)
 026        {
 027            ((BufferedAsyncEnumerable)state.Current.ReturnValue!)._buffer.Add(value);
 028        }
 29
 030        internal override bool SupportsCreateObjectDelegate => false;
 31        protected override void CreateCollection(ref Utf8JsonReader reader, scoped ref ReadStack state, JsonSerializerOp
 032        {
 033            state.Current.ReturnValue = new BufferedAsyncEnumerable();
 034        }
 35
 36        internal override bool OnTryWrite(Utf8JsonWriter writer, TAsyncEnumerable value, JsonSerializerOptions options, 
 037        {
 038            if (!state.SupportAsync)
 039            {
 040                ThrowHelper.ThrowNotSupportedException_TypeRequiresAsyncSerialization(Type);
 41            }
 42
 043            return base.OnTryWrite(writer, value, options, ref state);
 044        }
 45
 46        [Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly", Justification = "Con
 47        protected override bool OnWriteResume(Utf8JsonWriter writer, TAsyncEnumerable value, JsonSerializerOptions optio
 048        {
 49            IAsyncEnumerator<TElement> enumerator;
 50            ValueTask<bool> moveNextTask;
 51
 052            if (state.Current.AsyncDisposable is null)
 053            {
 054                enumerator = value.GetAsyncEnumerator(state.CancellationToken);
 55                // async enumerators can only be disposed asynchronously;
 56                // store in the WriteStack for future disposal
 57                // by the root async serialization context.
 058                state.Current.AsyncDisposable = enumerator;
 59                // enumerator.MoveNextAsync() calls can throw,
 60                // ensure the enumerator already is stored
 61                // in the WriteStack for proper disposal.
 062                moveNextTask = enumerator.MoveNextAsync();
 63
 064                if (!moveNextTask.IsCompleted)
 065                {
 66                    // It is common for first-time MoveNextAsync() calls to return pending tasks,
 67                    // since typically that is when underlying network connections are being established.
 68                    // For this case only, suppress flushing the current buffer contents (e.g. the leading '[' token of 
 69                    // to give the stream owner the ability to recover in case of a connection error.
 070                    state.SuppressFlush = true;
 071                    goto SuspendDueToPendingTask;
 72                }
 073            }
 74            else
 075            {
 076                Debug.Assert(state.Current.AsyncDisposable is IAsyncEnumerator<TElement>);
 077                enumerator = (IAsyncEnumerator<TElement>)state.Current.AsyncDisposable;
 78
 079                if (state.Current.AsyncEnumeratorIsPendingCompletion)
 080                {
 81                    // converter was previously suspended due to a pending MoveNextAsync() task
 082                    Debug.Assert(state.PendingTask is Task<bool> && state.PendingTask.IsCompleted);
 083                    moveNextTask = new ValueTask<bool>((Task<bool>)state.PendingTask);
 084                    state.Current.AsyncEnumeratorIsPendingCompletion = false;
 085                    state.PendingTask = null;
 086                }
 87                else
 088                {
 89                    // converter was suspended for a different reason;
 90                    // the last MoveNextAsync() call can only have completed with 'true'.
 091                    moveNextTask = new ValueTask<bool>(true);
 092                }
 093            }
 94
 095            Debug.Assert(moveNextTask.IsCompleted);
 096            JsonConverter<TElement> converter = GetElementConverter(ref state);
 97
 98            // iterate through the enumerator while elements are being returned synchronously
 99            do
 0100            {
 0101                if (!moveNextTask.Result)
 0102                {
 103                    // we have completed serialization for the enumerator,
 104                    // clear from the stack and schedule for async disposal.
 0105                    state.Current.AsyncDisposable = null;
 0106                    state.AddCompletedAsyncDisposable(enumerator);
 0107                    return true;
 108                }
 109
 0110                if (ShouldFlush(ref state, writer))
 0111                {
 0112                    return false;
 113                }
 114
 0115                TElement element = enumerator.Current;
 0116                if (!converter.TryWrite(writer, element, options, ref state))
 0117                {
 0118                    return false;
 119                }
 120
 0121                state.Current.EndCollectionElement();
 0122                moveNextTask = enumerator.MoveNextAsync();
 0123            } while (moveNextTask.IsCompleted);
 124
 0125        SuspendDueToPendingTask:
 126            // we have a pending MoveNextAsync() call;
 127            // wrap inside a regular task so that it can be awaited multiple times;
 128            // mark the current stackframe as pending completion.
 0129            Debug.Assert(state.PendingTask is null);
 0130            state.PendingTask = moveNextTask.AsTask();
 0131            state.Current.AsyncEnumeratorIsPendingCompletion = true;
 0132            return false;
 0133        }
 134
 135        private sealed class BufferedAsyncEnumerable : IAsyncEnumerable<TElement>
 136        {
 0137            public readonly List<TElement> _buffer = new();
 138
 139#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
 140            public async IAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken _)
 0141            {
 0142                foreach (TElement element in _buffer)
 0143                {
 0144                    yield return element;
 0145                }
 0146            }
 147#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
 148        }
 149    }
 150}