127 lines
4.9 KiB
C#
127 lines
4.9 KiB
C#
using PooledAwait.Internal;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace PooledAwait
|
|
{
|
|
/// <summary>
|
|
/// Like a ValueTaskCompletionSource<typeparamref name="T"/>, but the actual task will only become allocated
|
|
/// if the .Task is consumed; this is useful for APIs where the consumer *may* consume a task
|
|
/// </summary>
|
|
public readonly struct LazyTaskCompletionSource<T> : IDisposable
|
|
{
|
|
/// <summary><see cref="Object.Equals(Object)"/></summary>
|
|
public override bool Equals(object? obj) => obj is LazyTaskCompletionSource<T> ltcs && _state == ltcs._state && _token == ltcs._token;
|
|
/// <summary><see cref="Object.GetHashCode"/></summary>
|
|
public override int GetHashCode() => (_state == null ? 0 : _state.GetHashCode()) ^ _token;
|
|
/// <summary><see cref="Object.ToString"/></summary>
|
|
public override string ToString() => nameof(LazyTaskCompletionSource);
|
|
|
|
private readonly LazyTaskState<T> _state;
|
|
private readonly short _token;
|
|
|
|
/// <summary>
|
|
/// Gets the task associated with this instance
|
|
/// </summary>
|
|
public Task<T> Task => (Task<T>)(_state?.GetTask(_token) ?? ThrowHelper.ThrowInvalidOperationException<Task<T>>());
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private LazyTaskCompletionSource(LazyTaskState<T> state)
|
|
{
|
|
_state = state;
|
|
_token = state.Version;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a new instance; this instance should be disposed when it is known to be unwanted
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static LazyTaskCompletionSource<T> Create()
|
|
=> new LazyTaskCompletionSource<T>(LazyTaskState<T>.Create());
|
|
|
|
/// <summary>
|
|
/// Create a new instance; this instance will never by recycled
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static LazyTaskCompletionSource<T> CreateConstant(T value)
|
|
=> new LazyTaskCompletionSource<T>(LazyTaskState<T>.CreateConstant(value));
|
|
|
|
|
|
private static LazyTaskCompletionSource<T> _canceled;
|
|
|
|
/// <summary>
|
|
/// A global LazyTaskCompletionSource that represents a cancelled operation
|
|
/// </summary>
|
|
public static LazyTaskCompletionSource<T> CanceledTask
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _canceled.IsValid ? _canceled : _canceled = new LazyTaskCompletionSource<T>(LazyTaskState<T>.CreateCanceled());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TrySetResult(T result) => _state?.TrySetResult(_token, result) == true;
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetResult(T result)
|
|
{
|
|
if (!TrySetResult(result)) ThrowHelper.ThrowInvalidOperationException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
|
=> _state?.TrySetCanceled(_token, cancellationToken) == true;
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetCanceled(CancellationToken cancellationToken = default)
|
|
{
|
|
if (!TrySetCanceled(cancellationToken)) ThrowHelper.ThrowInvalidOperationException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TrySetException(Exception exception) => _state?.TrySetException(_token, exception) == true;
|
|
|
|
/// <summary>
|
|
/// Set the result of the operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetException(Exception exception)
|
|
{
|
|
if (!TrySetException(exception)) ThrowHelper.ThrowInvalidOperationException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Release all resources associated with this operation
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Dispose() => _state?.Recycle(_token);
|
|
|
|
internal bool IsValid => _state?.IsValid(_token) == true;
|
|
internal bool HasSource => _state?.HasSource == true;
|
|
internal bool HasTask => _state?.HasTask == true;
|
|
|
|
/// <summary>
|
|
/// Indicates whether this is an invalid default instance
|
|
/// </summary>
|
|
public bool IsNull
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _state == null;
|
|
}
|
|
}
|
|
}
|