Created
April 22, 2024 08:59
-
-
Save aalmada/784ca7948e80ea8558e993050ff00ba2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Threading.Tasks; | |
var root = ParallelAll([ | |
Invert(Repeat(WriteLineRange(0, 4), 2)), | |
WriteLineRange(10, 10), | |
]); | |
await foreach(var _ in root) | |
{ | |
Console.WriteLine("-"); | |
} | |
static async IAsyncEnumerable<BehaviorStatus> Succeed() | |
{ | |
yield return BehaviorStatus.Succeeded; | |
} | |
static async IAsyncEnumerable<BehaviorStatus> Fail() | |
{ | |
yield return BehaviorStatus.Failed; | |
} | |
static IAsyncEnumerable<BehaviorStatus> Sequence(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
ArgumentNullException.ThrowIfNull(children); | |
return GetEnumerable(children); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
for(var index = 0; index < children.Length; index++) | |
{ | |
var child = children[index]; | |
await foreach(var status in child.ConfigureAwait(false)) | |
{ | |
switch(status) | |
{ | |
case BehaviorStatus.Running: | |
yield return BehaviorStatus.Running; | |
break; | |
case BehaviorStatus.Succeeded: | |
goto childSucceeded; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Failed; | |
yield break; | |
} | |
} | |
childSucceeded: | |
if(index < children.Length - 1) | |
yield return BehaviorStatus.Running; | |
} | |
yield return BehaviorStatus.Succeeded; | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> Select(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
ArgumentNullException.ThrowIfNull(children); | |
return GetEnumerable(children); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
for(var index = 0; index < children.Length; index++) | |
{ | |
var child = children[index]; | |
await foreach(var status in child.ConfigureAwait(false)) | |
{ | |
switch(status) | |
{ | |
case BehaviorStatus.Running: | |
yield return BehaviorStatus.Running; | |
break; | |
case BehaviorStatus.Succeeded: | |
yield return BehaviorStatus.Succeeded; | |
yield break; | |
case BehaviorStatus.Failed: | |
goto childFailed; | |
} | |
} | |
childFailed: | |
if(index < children.Length - 1) | |
yield return BehaviorStatus.Running; | |
} | |
yield return BehaviorStatus.Failed; | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> ParallelAny(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
ArgumentNullException.ThrowIfNull(children); | |
return GetEnumerable(children); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
var enumerators = new IAsyncEnumerator<BehaviorStatus>[children.Length]; | |
for (var index = 0; index < enumerators.Length && index < children.Length; index++) | |
enumerators[index] = children[index].GetAsyncEnumerator(); | |
try | |
{ | |
while(true) | |
{ | |
foreach(var enumerator in enumerators) | |
{ | |
await enumerator.MoveNextAsync().ConfigureAwait(false); | |
switch(enumerator.Current) | |
{ | |
case BehaviorStatus.Succeeded: | |
yield return BehaviorStatus.Succeeded; | |
yield break; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Failed; | |
yield break; | |
} | |
} | |
yield return BehaviorStatus.Running; | |
} | |
} | |
finally | |
{ | |
foreach(var enumerator in enumerators) | |
await enumerator.DisposeAsync().ConfigureAwait(false); | |
} | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> ParallelAll(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
ArgumentNullException.ThrowIfNull(children); | |
return GetEnumerable(children); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus>[] children) | |
{ | |
var enumerators = new BehaviorEnumerator[children.Length]; | |
for (var index = 0; index < enumerators.Length && index < children.Length; index++) | |
enumerators[index] = new BehaviorEnumerator { Instance = children[index].GetAsyncEnumerator() }; | |
try | |
{ | |
var succeededCounter = 0; | |
while(true) | |
{ | |
foreach(var enumerator in enumerators) | |
{ | |
if(!enumerator.Succeeded) | |
{ | |
await enumerator.Instance.MoveNextAsync().ConfigureAwait(false); | |
switch(enumerator.Instance.Current) | |
{ | |
case BehaviorStatus.Succeeded: | |
enumerator.Succeeded = true; | |
succeededCounter++; | |
if(succeededCounter == children.Length) | |
{ | |
yield return BehaviorStatus.Succeeded; | |
yield break; | |
} | |
break; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Failed; | |
yield break; | |
} | |
} | |
} | |
yield return BehaviorStatus.Running; | |
} | |
} | |
finally | |
{ | |
foreach(var enumerator in enumerators) | |
await enumerator.Instance.DisposeAsync().ConfigureAwait(false); | |
} | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> Invert(IAsyncEnumerable<BehaviorStatus> child) | |
{ | |
ArgumentNullException.ThrowIfNull(child); | |
return GetEnumerable(child); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus> child) | |
{ | |
await foreach(var status in child.ConfigureAwait(false)) | |
{ | |
switch(status) | |
{ | |
case BehaviorStatus.Running: | |
yield return BehaviorStatus.Running; | |
break; | |
case BehaviorStatus.Succeeded: | |
yield return BehaviorStatus.Failed; | |
yield break; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Succeeded; | |
yield break; | |
} | |
} | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> Repeat(IAsyncEnumerable<BehaviorStatus> child, int count) | |
{ | |
ArgumentNullException.ThrowIfNull(child); | |
ArgumentOutOfRangeException.ThrowIfNegative(count); | |
return GetEnumerable(child, count); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus> child, int count) | |
{ | |
for(var counter = 0; counter < count; counter++) | |
{ | |
await foreach(var status in child.ConfigureAwait(false)) | |
{ | |
switch(status) | |
{ | |
case BehaviorStatus.Running: | |
yield return BehaviorStatus.Running; | |
break; | |
case BehaviorStatus.Succeeded: | |
goto childSucceeded; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Failed; | |
yield break; | |
} | |
} | |
childSucceeded: | |
if(counter < count - 1) | |
yield return BehaviorStatus.Running; | |
} | |
yield return BehaviorStatus.Succeeded; | |
} | |
} | |
static IAsyncEnumerable<BehaviorStatus> RepeatUntilFail(IAsyncEnumerable<BehaviorStatus> child) | |
{ | |
ArgumentNullException.ThrowIfNull(child); | |
return GetEnumerable(child); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(IAsyncEnumerable<BehaviorStatus> child) | |
{ | |
while(true) | |
{ | |
await foreach(var status in child.ConfigureAwait(false)) | |
{ | |
switch(status) | |
{ | |
case BehaviorStatus.Running: | |
yield return BehaviorStatus.Running; | |
break; | |
case BehaviorStatus.Succeeded: | |
goto childSucceeded; | |
case BehaviorStatus.Failed: | |
yield return BehaviorStatus.Succeeded; | |
yield break; | |
} | |
} | |
childSucceeded: | |
yield return BehaviorStatus.Running; | |
} | |
} | |
} | |
static async IAsyncEnumerable<BehaviorStatus> WriteLine(string? message) | |
{ | |
Console.WriteLine(message); | |
yield return BehaviorStatus.Succeeded; | |
} | |
static IAsyncEnumerable<BehaviorStatus> WriteLineRange(int start, int count) | |
{ | |
ArgumentOutOfRangeException.ThrowIfNegative(count); | |
return GetEnumerable(start, count); | |
static async IAsyncEnumerable<BehaviorStatus> GetEnumerable(int start, int count) | |
{ | |
var end = start + count; | |
for(var value = start; value < end; value++) | |
{ | |
Console.WriteLine(value); | |
if(value < end - 1) | |
yield return BehaviorStatus.Running; | |
} | |
yield return BehaviorStatus.Succeeded; | |
} | |
} | |
enum BehaviorStatus { Running, Succeeded, Failed }; | |
class BehaviorEnumerator | |
{ | |
public required IAsyncEnumerator<BehaviorStatus> Instance { get; init; } | |
public bool Succeeded { get; set; } = false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment