File: System\IO\Pipelines\PipeCompletion.cs
Web Access
Project: src\src\libraries\System.IO.Pipelines\src\System.IO.Pipelines.csproj (System.IO.Pipelines)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
 
namespace System.IO.Pipelines
{
    [DebuggerDisplay("IsCompleted = {" + nameof(IsCompleted) + "}")]
    internal struct PipeCompletion
    {
        private static readonly object s_completedSuccessfully = new object();
 
        private object? _state;
        private List<PipeCompletionCallback>? _callbacks;
 
        public bool IsCompleted => _state != null;
 
        public bool IsFaulted => _state is ExceptionDispatchInfo;
 
        public PipeCompletionCallbacks? TryComplete(Exception? exception = null)
        {
            if (_state == null)
            {
                if (exception != null)
                {
                    _state = ExceptionDispatchInfo.Capture(exception);
                }
                else
                {
                    _state = s_completedSuccessfully;
                }
            }
 
            return GetCallbacks();
        }
 
        public PipeCompletionCallbacks? AddCallback(Action<Exception?, object?> callback, object? state)
        {
            _callbacks ??= new List<PipeCompletionCallback>();
            _callbacks.Add(new PipeCompletionCallback(callback, state));
 
            if (IsCompleted)
            {
                return GetCallbacks();
            }
 
            return null;
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsCompletedOrThrow()
        {
            if (!IsCompleted)
            {
                return false;
            }
 
            if (_state is ExceptionDispatchInfo edi)
            {
                edi.Throw();
            }
 
            return true;
        }
 
        private PipeCompletionCallbacks? GetCallbacks()
        {
            Debug.Assert(IsCompleted);
 
            var callbacks = _callbacks;
            if (callbacks == null)
            {
                return null;
            }
 
            _callbacks = null;
 
            return new PipeCompletionCallbacks(callbacks, _state as ExceptionDispatchInfo);
        }
 
        public void Reset()
        {
            Debug.Assert(IsCompleted);
            Debug.Assert(_callbacks == null);
            _state = null;
        }
 
        public override string ToString()
        {
            return $"{nameof(IsCompleted)}: {IsCompleted}";
        }
    }
}