namespace BrokenAsyncMethodBuilder
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
[AsyncMethodBuilder(typeof(CustomAwaitableAsyncMethodBuilder<>))]
public readonly struct CustomAwaitable<T>
readonly ValueTask<T> _valueTask;
public CustomAwaitable(ValueTask<T> valueTask)
public ValueTaskAwaiter<T> GetAwaiter() => _valueTask.GetAwaiter();
public struct CustomAwaitableAsyncMethodBuilder<T>
TaskCompletionSource<T>? _source;
public CustomAwaitable<T> Task
_lock.Enter(ref lockTaken);
if (_exception is not null)
return new CustomAwaitable<T>(ValueTask.FromException<T>(_exception));
return new CustomAwaitable<T>(ValueTask.FromResult(_result!));
return new CustomAwaitable<T>(
(_source ??= new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously))
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
awaiter.OnCompleted(stateMachine.MoveNext);
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
public static CustomAwaitableAsyncMethodBuilder<T> Create() => new()
_lock = new SpinLock(Debugger.IsAttached)
public void SetException(Exception exception)
_lock.Enter(ref lockTaken);
if (Volatile.Read(ref _source) is {} source)
source.TrySetException(exception);
public void SetResult(T result)
_lock.Enter(ref lockTaken);
if (Volatile.Read(ref _source) is {} source)
source.TrySetResult(result);
public void SetStateMachine(IAsyncStateMachine stateMachine) {}
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine => stateMachine.MoveNext();
var expected = Guid.NewGuid().ToString();
async CustomAwaitable<string> GetValueAsync()
var actual = await GetValueAsync();
if (!ReferenceEquals(expected, actual))
Console.WriteLine("Done!");