< Summary

Class:Azure.Core.Pipeline.TaskExtensions
Assembly:Azure.DigitalTwins.Core
File(s):C:\Git\azure-sdk-for-net\sdk\core\Azure.Core\src\Shared\TaskExtensions.cs
Covered lines:2
Uncovered lines:79
Coverable lines:81
Total lines:286
Line coverage:2.4% (2 of 81)
Covered branches:1
Total branches:30
Branch coverage:3.3% (1 of 30)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
AwaitWithCancellation(...)-0%100%
AwaitWithCancellation(...)-0%100%
EnsureCompleted(...)-0%0%
EnsureCompleted(...)-0%0%
EnsureCompleted(...)-66.67%50%
EnsureCompleted(...)-0%0%
EnsureSyncEnumerable(...)-0%100%
EnsureCompleted(...)-0%100%
EnsureCompleted(...)-0%100%
VerifyTaskCompleted(...)-0%0%
HasSynchronizationContext()-0%0%
.ctor(...)-0%100%
GetEnumerator()-0%100%
System.Collections.Generic.IEnumerable<T>.GetEnumerator()-0%100%
System.Collections.IEnumerable.GetEnumerator()-0%100%
.ctor(...)-0%100%
MoveNext()-0%100%
Reset()-0%100%
get_Current()-0%100%
System.Collections.IEnumerator.get_Current()-0%100%
Dispose()-0%100%
.ctor(...)-0%100%
GetAwaiter()-0%100%
.ctor(...)-0%100%
GetAwaiter()-0%100%
.ctor(...)-0%100%
get_IsCompleted()-0%0%
OnCompleted(...)-0%100%
UnsafeOnCompleted(...)-0%100%
GetResult()-0%0%
WrapContinuation(...)-0%0%
.ctor(...)-0%100%
get_IsCompleted()-0%0%
OnCompleted(...)-0%100%
UnsafeOnCompleted(...)-0%100%
GetResult()-0%0%
WrapContinuation(...)-0%0%
.ctor(...)-0%100%
get_Continuation()-0%100%
ContinuationImplementation()-0%0%

File(s)

C:\Git\azure-sdk-for-net\sdk\core\Azure.Core\src\Shared\TaskExtensions.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4#nullable disable
 5
 6using System;
 7using System.Collections;
 8using System.Collections.Generic;
 9using System.Diagnostics;
 10using System.Runtime.CompilerServices;
 11using System.Threading;
 12using System.Threading.Tasks;
 13
 14namespace Azure.Core.Pipeline
 15{
 16    internal static class TaskExtensions
 17    {
 18        public static WithCancellationTaskAwaitable<T> AwaitWithCancellation<T>(this Task<T> task, CancellationToken can
 019            => new WithCancellationTaskAwaitable<T>(task, cancellationToken);
 20
 21        public static WithCancellationValueTaskAwaitable<T> AwaitWithCancellation<T>(this ValueTask<T> task, Cancellatio
 022            => new WithCancellationValueTaskAwaitable<T>(task, cancellationToken);
 23
 24        public static T EnsureCompleted<T>(this Task<T> task)
 25        {
 26#if DEBUG
 27            VerifyTaskCompleted(task.IsCompleted);
 28#else
 029            if (HasSynchronizationContext())
 30            {
 031                throw new InvalidOperationException("Synchronously waiting on non-completed task isn't allowed.");
 32            }
 33#endif
 34#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 035            return task.GetAwaiter().GetResult();
 36#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 37        }
 38
 39        public static void EnsureCompleted(this Task task)
 40        {
 41#if DEBUG
 42            VerifyTaskCompleted(task.IsCompleted);
 43#else
 044            if (HasSynchronizationContext())
 45            {
 046                throw new InvalidOperationException("Synchronously waiting on non-completed task isn't allowed.");
 47            }
 48#endif
 49#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 050            task.GetAwaiter().GetResult();
 51#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 052        }
 53
 54        public static T EnsureCompleted<T>(this ValueTask<T> task)
 55        {
 7456            if (!task.IsCompleted)
 57            {
 58#pragma warning disable AZC0107 // public asynchronous method shouldn't be called in synchronous scope. Use synchronous 
 059                return EnsureCompleted(task.AsTask());
 60#pragma warning restore AZC0107 // public asynchronous method shouldn't be called in synchronous scope. Use synchronous 
 61            }
 62#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 7463            return task.GetAwaiter().GetResult();
 64#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 65        }
 66
 67        public static void EnsureCompleted(this ValueTask task)
 68        {
 069            if (!task.IsCompleted)
 70            {
 71#pragma warning disable AZC0107 // public asynchronous method shouldn't be called in synchronous scope. Use synchronous 
 072                EnsureCompleted(task.AsTask());
 73#pragma warning restore AZC0107 // public asynchronous method shouldn't be called in synchronous scope. Use synchronous 
 74            }
 75            else
 76            {
 77#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 078                task.GetAwaiter().GetResult();
 79#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extensi
 80            }
 081        }
 82
 083        public static Enumerable<T> EnsureSyncEnumerable<T>(this IAsyncEnumerable<T> asyncEnumerable) => new Enumerable<
 84
 85        public static ConfiguredValueTaskAwaitable<T> EnsureCompleted<T>(this ConfiguredValueTaskAwaitable<T> awaitable,
 86        {
 087            if (!async)
 88            {
 89#if DEBUG
 90                VerifyTaskCompleted(awaitable.GetAwaiter().IsCompleted);
 91#endif
 92            }
 093            return awaitable;
 94        }
 95
 96        public static ConfiguredValueTaskAwaitable EnsureCompleted(this ConfiguredValueTaskAwaitable awaitable, bool asy
 97        {
 98
 099            if (!async)
 100            {
 101#if DEBUG
 102                VerifyTaskCompleted(awaitable.GetAwaiter().IsCompleted);
 103#endif
 104            }
 0105            return awaitable;
 106        }
 107
 108        [Conditional("DEBUG")]
 109        private static void VerifyTaskCompleted(bool isCompleted)
 110        {
 0111            if (!isCompleted)
 112            {
 0113                if (Debugger.IsAttached)
 114                {
 0115                    Debugger.Break();
 116                }
 117                // Throw an InvalidOperationException instead of using
 118                // Debug.Assert because that brings down nUnit immediately
 0119                throw new InvalidOperationException("Task is not completed");
 120            }
 0121        }
 122
 123        private static bool HasSynchronizationContext()
 0124            => SynchronizationContext.Current != null && SynchronizationContext.Current.GetType() != typeof(Synchronizat
 125
 126        /// <summary>
 127        /// Both <see cref="Enumerable{T}"/> and <see cref="Enumerator{T}"/> are defined as public structs so that forea
 128        /// to call <see cref="Enumerable{T}.GetEnumerator"/> and avoid heap memory allocation.
 129        /// Please don't delete this method and don't make these types private.
 130        /// </summary>
 131        /// <typeparam name="T"></typeparam>
 132        public readonly struct Enumerable<T> : IEnumerable<T>
 133        {
 134            private readonly IAsyncEnumerable<T> _asyncEnumerable;
 135
 0136            public Enumerable(IAsyncEnumerable<T> asyncEnumerable) => _asyncEnumerable = asyncEnumerable;
 137
 0138            public Enumerator<T> GetEnumerator() => new Enumerator<T>(_asyncEnumerable.GetAsyncEnumerator());
 139
 0140            IEnumerator<T> IEnumerable<T>.GetEnumerator() => new Enumerator<T>(_asyncEnumerable.GetAsyncEnumerator());
 141
 0142            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 143        }
 144
 145        public readonly struct Enumerator<T> : IEnumerator<T>
 146        {
 147            private readonly IAsyncEnumerator<T> _asyncEnumerator;
 148
 0149            public Enumerator(IAsyncEnumerator<T> asyncEnumerator) => _asyncEnumerator = asyncEnumerator;
 150
 151#pragma warning disable AZC0107 // Do not call public asynchronous method in synchronous scope.
 0152            public bool MoveNext() => _asyncEnumerator.MoveNextAsync().EnsureCompleted();
 153#pragma warning restore AZC0107 // Do not call public asynchronous method in synchronous scope.
 154
 0155            public void Reset() => throw new NotSupportedException($"{GetType()} is a synchronous wrapper for {_asyncEnu
 156
 0157            public T Current => _asyncEnumerator.Current;
 158
 0159            object IEnumerator.Current => Current;
 160
 161#pragma warning disable AZC0107 // Do not call public asynchronous method in synchronous scope.
 0162            public void Dispose() => _asyncEnumerator.DisposeAsync().EnsureCompleted();
 163#pragma warning restore AZC0107 // Do not call public asynchronous method in synchronous scope.
 164        }
 165
 166        public readonly struct WithCancellationTaskAwaitable<T>
 167        {
 168            private readonly CancellationToken _cancellationToken;
 169            private readonly ConfiguredTaskAwaitable<T> _awaitable;
 170
 171            public WithCancellationTaskAwaitable(Task<T> task, CancellationToken cancellationToken)
 172            {
 0173                _awaitable = task.ConfigureAwait(false);
 0174                _cancellationToken = cancellationToken;
 0175            }
 176
 0177            public WithCancellationTaskAwaiter<T> GetAwaiter() => new WithCancellationTaskAwaiter<T>(_awaitable.GetAwait
 178        }
 179
 180        public readonly struct WithCancellationValueTaskAwaitable<T>
 181        {
 182            private readonly CancellationToken _cancellationToken;
 183            private readonly ConfiguredValueTaskAwaitable<T> _awaitable;
 184
 185            public WithCancellationValueTaskAwaitable(ValueTask<T> task, CancellationToken cancellationToken)
 186            {
 0187                _awaitable = task.ConfigureAwait(false);
 0188                _cancellationToken = cancellationToken;
 0189            }
 190
 0191            public WithCancellationValueTaskAwaiter<T> GetAwaiter() => new WithCancellationValueTaskAwaiter<T>(_awaitabl
 192        }
 193
 194        public readonly struct WithCancellationTaskAwaiter<T> : ICriticalNotifyCompletion
 195        {
 196            private readonly CancellationToken _cancellationToken;
 197            private readonly ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter _taskAwaiter;
 198
 199            public WithCancellationTaskAwaiter(ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter awaiter, CancellationTok
 200            {
 0201                _taskAwaiter = awaiter;
 0202                _cancellationToken = cancellationToken;
 0203            }
 204
 0205            public bool IsCompleted => _taskAwaiter.IsCompleted || _cancellationToken.IsCancellationRequested;
 206
 0207            public void OnCompleted(Action continuation) => _taskAwaiter.OnCompleted(WrapContinuation(continuation));
 208
 0209            public void UnsafeOnCompleted(Action continuation) => _taskAwaiter.UnsafeOnCompleted(WrapContinuation(contin
 210
 211            public T GetResult()
 212            {
 213                Debug.Assert(IsCompleted);
 0214                if (!_taskAwaiter.IsCompleted)
 215                {
 0216                    _cancellationToken.ThrowIfCancellationRequested();
 217                }
 0218                return _taskAwaiter.GetResult();
 219            }
 220
 221            private Action WrapContinuation(in Action originalContinuation)
 0222                => _cancellationToken.CanBeCanceled
 0223                    ? new WithCancellationContinuationWrapper(originalContinuation, _cancellationToken).Continuation
 0224                    : originalContinuation;
 225        }
 226
 227        public readonly struct WithCancellationValueTaskAwaiter<T> : ICriticalNotifyCompletion
 228        {
 229            private readonly CancellationToken _cancellationToken;
 230            private readonly ConfiguredValueTaskAwaitable<T>.ConfiguredValueTaskAwaiter _taskAwaiter;
 231
 232            public WithCancellationValueTaskAwaiter(ConfiguredValueTaskAwaitable<T>.ConfiguredValueTaskAwaiter awaiter, 
 233            {
 0234                _taskAwaiter = awaiter;
 0235                _cancellationToken = cancellationToken;
 0236            }
 237
 0238            public bool IsCompleted => _taskAwaiter.IsCompleted || _cancellationToken.IsCancellationRequested;
 239
 0240            public void OnCompleted(Action continuation) => _taskAwaiter.OnCompleted(WrapContinuation(continuation));
 241
 0242            public void UnsafeOnCompleted(Action continuation) => _taskAwaiter.UnsafeOnCompleted(WrapContinuation(contin
 243
 244            public T GetResult()
 245            {
 246                Debug.Assert(IsCompleted);
 0247                if (!_taskAwaiter.IsCompleted)
 248                {
 0249                    _cancellationToken.ThrowIfCancellationRequested();
 250                }
 0251                return _taskAwaiter.GetResult();
 252            }
 253
 254            private Action WrapContinuation(in Action originalContinuation)
 0255                => _cancellationToken.CanBeCanceled
 0256                    ? new WithCancellationContinuationWrapper(originalContinuation, _cancellationToken).Continuation
 0257                    : originalContinuation;
 258        }
 259
 260        private class WithCancellationContinuationWrapper
 261        {
 262            private Action _originalContinuation;
 263            private readonly CancellationTokenRegistration _registration;
 264
 0265            public WithCancellationContinuationWrapper(Action originalContinuation, CancellationToken cancellationToken)
 266            {
 0267                Action continuation = ContinuationImplementation;
 0268                _originalContinuation = originalContinuation;
 0269                _registration = cancellationToken.Register(continuation);
 0270                Continuation = continuation;
 0271            }
 272
 0273            public Action Continuation { get; }
 274
 275            private void ContinuationImplementation()
 276            {
 0277                Action originalContinuation = Interlocked.Exchange(ref _originalContinuation, null);
 0278                if (originalContinuation != null)
 279                {
 0280                    _registration.Dispose();
 0281                    originalContinuation();
 282                }
 0283            }
 284        }
 285    }
 286}