// Code quality of this file: low. // We need an annotation on lambdas to lift them to equatable singletons. using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Immutable { public static partial class ImmutableEnumeratorExtensionMethods { public static IImmutableEnumerator ToImmutableEnumerator(this IEnumerator e) => ImmutableEnumerator.Make(e); public static IImmutableEnumerator GetImmutableEnumerator(this IEnumerable e) => e.GetEnumerator().ToImmutableEnumerator(); public static Option>> FirstAndRest(this IImmutableEnumerator e) => e.MoveNext() .Match( None: () => Option.None>>(), Some: elt => new Tuple>( elt.First, elt.Rest ).Some() ); public static IEnumerable ToIEnumerable(this IImmutableEnumerator e) { var next = e.MoveNext(); while (next.IsSome) { var elem = next.ElseThrow(new Exception("impossible")); yield return elem.First; next = elem.Rest.MoveNext(); } } [F] private partial class TakeUntil_ { public Option>> F( ValueTuple /*e*/, IEqF, bool> /*predicate*/> t ) => t.Item2.F(t.Item1) ? Option.None>>() : t.Item1.MoveNext().IfSome(next => new Tuple>( next.First, TakeUntil(next.Rest, t.Item2))); } public static IImmutableEnumerator TakeUntil(this IImmutableEnumerator e, IEqF, bool> predicate) => new PureImmutableEnumerator< ValueTuple< IImmutableEnumerator, IEqF, bool> >, T>( (e, predicate), TakeUntil_.Eq); [F] private partial class Empty_ { public Option>> F( Unit _ ) => Option.None>>(); } public static IImmutableEnumerator Empty() => new PureImmutableEnumerator( Unit.unit, Empty_.Eq); [F] private partial class ImSingleton_ { public Option>> F( T value ) => new Tuple>( value, Empty() ).Some(); } public static IImmutableEnumerator ImSingleton(this T value) => new PureImmutableEnumerator( value, ImSingleton_.Eq); [F] private partial class Concat_ { public Option>> F( ValueTuple, /*e1*/ IImmutableEnumerator /*e2*/> t ) => t.Item1.MoveNext().Match( Some: element => new Tuple>( element.First, element.Rest.Concat(t.Item2) ).Some(), None: () => t.Item2.MoveNext().IfSome(element => new Tuple>( element.First, element.Rest))); } public static IImmutableEnumerator Concat(this IImmutableEnumerator e1, IImmutableEnumerator e2) => new PureImmutableEnumerator< ValueTuple< IImmutableEnumerator /*e1*/, IImmutableEnumerator /*e2*/ >, T>( (e1, e2), Concat_.Eq); [F] private partial class Lazy_ { public Option>> F( ValueTuple> /*f*/> t ) => t.Item2.F(t.Item1).MoveNext().IfSome(element => new Tuple>( element.First, element.Rest )); } // Apply a transformation to an immutable enumerator. // The transformation function is only called when the // result is stepped. It should only step its input // enough to produce one element, but not more. public static IImmutableEnumerator Lazy( this IImmutableEnumerator e, IEqF, IImmutableEnumerator> f) => new PureImmutableEnumerator< ValueTuple< IImmutableEnumerator /*e*/, IEqF, IImmutableEnumerator> /*f*/ >, U>( (e, f), Lazy_, U>.Eq); public static IImmutableEnumerator Lazy( this IImmutableEnumerator e, IEqF< ValueTuple /*e*/, V /*v*/>, IImmutableEnumerator > f, V v) => new PureImmutableEnumerator< ValueTuple< ValueTuple /*e*/, V /*v*/>, IEqF< ValueTuple /*e*/, V /*v*/>, IImmutableEnumerator> /*f*/ >, U>( ((e, v), f), Lazy_, V>, U>.Eq); [F] private partial class Flatten_ { public IImmutableEnumerator F( IImmutableEnumerator> e ) => e.MoveNext().Match( Some: element => element.First.Concat(element.Rest.Flatten()), None: () => Empty()); } public static IImmutableEnumerator Flatten(this IImmutableEnumerator> e) => e.Lazy(Flatten_.Eq); [F] private partial class Select_ { public IImmutableEnumerator F( ValueTuple /*e*/, IEqF>, U> /*f*/> t ) => t.Item1.MoveNext().Match( Some: element => t.Item2.F((element.First, t.Item1)).ImSingleton().Concat( element.Rest.Select(t.Item2)), None: () => Empty()); } public static IImmutableEnumerator Select(this IImmutableEnumerator e, IEqF>, U> f) => Lazy(e, Select_.Eq, f); [F] private partial class SelectAggregate_ { public IImmutableEnumerator F( ValueTuple /*e*/, ValueTuple>, ValueTuple> /*f*/>> t ) { var (e, accf) = t; var (acc, f) = accf; return e.MoveNext().Match( Some: element => { var res = f.F(acc, (element.First, e)); var newAcc = res.Item1; var result = res.Item2; return result.ImSingleton().Concat( element.Rest.SelectAggregate(newAcc, f)); }, None: () => Empty()); } } public static IImmutableEnumerator SelectAggregate(this IImmutableEnumerator e, A acc, IEqF>, ValueTuple> f) => Lazy(e, SelectAggregate_.Eq, (acc, f)); } }