Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@zawodskoj
Last active March 1, 2021 00:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zawodskoj/0ec372cafded23e43356edac26584d83 to your computer and use it in GitHub Desktop.
Save zawodskoj/0ec372cafded23e43356edac26584d83 to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
internal struct MaybeMethodBuilder<T>
{
private Maybe<T> _task;
public static MaybeMethodBuilder<T> Create() => new MaybeMethodBuilder<T>();
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
// idk what is this
}
public void SetException(Exception exception)
{
// just rethrow an exception
throw new AggregateException(exception);
}
public void SetResult(T result) => _task = new Maybe<T>(result);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : struct, MaybeAwaiter<T>.IConstraint
{
// AwaitOnCompleted call means that `MaybeAwaiter` has `Empty` value
// doing nothing
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : struct, MaybeAwaiter<T>.IConstraint
{
// this method could not be called due to constraints
throw new NotSupportedException();
}
public Maybe<T> Task => _task;
}
struct MaybeAwaiter<T> : INotifyCompletion, MaybeAwaiter<T>.IConstraint
{
public interface IConstraint { }
private readonly Maybe<T> _value;
public MaybeAwaiter(Maybe<T> value) => _value = value;
public bool IsCompleted => _value.HasValue;
public void OnCompleted(Action continuation) {}
public T GetResult() => _value.UnwrapOr(default);
}
[AsyncMethodBuilder(typeof(MaybeMethodBuilder<>))]
struct Maybe<T> {
private readonly T _value;
private readonly bool _hasSmth;
public static readonly Maybe<T> Empty = new Maybe<T>(default, false);
private Maybe(T value, bool hasSmth) {
_value = value;
_hasSmth = hasSmth;
}
public Maybe(T value) : this(value, true) {}
public bool HasValue => _hasSmth;
public T UnwrapOr(T val) => _hasSmth ? _value : val;
public MaybeAwaiter<T> GetAwaiter() => new MaybeAwaiter<T>(this);
}
class Program
{
static async Maybe<int> SumMaybes(Maybe<int> a, Maybe<int> b)
{
var av = await a;
var bv = await b;
return av + bv;
}
static async Maybe<int> SumMaybesNoThrow()
{
await Maybe<int>.Empty;
throw new Exception("Should not be thrown");
}
static async Maybe<int> SumMaybesAsync(Maybe<int> a, Maybe<int> b)
{
await Task.Delay(1000);
return await SumMaybes(a, b);
}
public static void Main() {
Console.WriteLine(SumMaybes(new Maybe<int>(123), new Maybe<int>(456)).UnwrapOr(0));
Console.WriteLine(SumMaybesNoThrow().UnwrapOr(-1));
Console.WriteLine(SumMaybesAsync(new Maybe<int>(123), Maybe<int>.Empty).UnwrapOr(-1));
Console.WriteLine("DONE");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment