瀏覽代碼

AppendPrepend

Oren Novotny 9 年之前
父節點
當前提交
169e9176a6
共有 2 個文件被更改,包括 1102 次插入0 次删除
  1. 510 0
      Ix.NET/Source/System.Interactive.Async/AppendPrepend.cs
  2. 592 0
      Ix.NET/Source/Tests/AppendPrependTests.cs

+ 510 - 0
Ix.NET/Source/System.Interactive.Async/AppendPrepend.cs

@@ -0,0 +1,510 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Linq
+{
+    public static partial class AsyncEnumerable
+    {
+        public static IAsyncEnumerable<TSource> Append<TSource>(this IAsyncEnumerable<TSource> source, TSource element)
+        {
+            if (source == null)
+                throw new ArgumentNullException(nameof(source));
+
+            var appendable = source as AppendPrepentAsyncIterator<TSource>;
+            if (appendable != null)
+            {
+                return appendable.Append(element);
+            }
+
+            return new AppendPrepend1AsyncIterator<TSource>(source, element, true);
+        }
+
+        public static IAsyncEnumerable<TSource> Prepend<TSource>(this IAsyncEnumerable<TSource> source, TSource element)
+        {
+            if (source == null)
+                throw new ArgumentNullException(nameof(source));
+
+            var appendable = source as AppendPrepentAsyncIterator<TSource>;
+            if (appendable != null)
+            {
+                return appendable.Prepend(element);
+            }
+
+            return new AppendPrepend1AsyncIterator<TSource>(source, element, false);
+        }
+
+        private abstract class AppendPrepentAsyncIterator<TSource> : AsyncIterator<TSource>, IIListProvider<TSource>
+        {
+            protected readonly IAsyncEnumerable<TSource> source;
+            protected IAsyncEnumerator<TSource> enumerator;
+
+            protected AppendPrepentAsyncIterator(IAsyncEnumerable<TSource> source)
+            {
+                Debug.Assert(source != null);
+
+                this.source = source;
+            }
+
+            protected void GetSourceEnumerator()
+            {
+                Debug.Assert(enumerator == null);
+                enumerator = source.GetEnumerator();
+            }
+
+            public abstract AppendPrepentAsyncIterator<TSource> Append(TSource item);
+            public abstract AppendPrepentAsyncIterator<TSource> Prepend(TSource item);
+
+            protected async Task<bool> LoadFromEnumerator(CancellationToken cancellationToken)
+            {
+                if (await enumerator.MoveNext(cancellationToken)
+                                    .ConfigureAwait(false))
+                {
+                    current = enumerator.Current;
+                    return true;
+                }
+
+                enumerator?.Dispose();
+                enumerator = null;
+
+                return false;
+            }
+
+            public override void Dispose()
+            {
+                if (enumerator != null)
+                {
+                    enumerator.Dispose();
+                    enumerator = null;
+                }
+
+                base.Dispose();
+            }
+
+            public abstract Task<TSource[]> ToArrayAsync(CancellationToken cancellationToken);
+            public abstract Task<List<TSource>> ToListAsync(CancellationToken cancellationToken);
+            public abstract Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken);
+        }
+
+        private sealed class AppendPrepend1AsyncIterator<TSource> : AppendPrepentAsyncIterator<TSource>
+        {
+            private readonly TSource item;
+            private readonly bool appending;
+
+            bool hasEnumerator;
+
+            public AppendPrepend1AsyncIterator(IAsyncEnumerable<TSource> source, TSource item, bool appending)
+                : base(source)
+            {
+                this.item = item;
+                this.appending = appending;
+            }
+
+            public override AsyncIterator<TSource> Clone()
+            {
+                return new AppendPrepend1AsyncIterator<TSource>(source, item, appending);
+            }
+
+
+            protected override async Task<bool> MoveNextCore(CancellationToken cancellationToken)
+            {
+                switch (state)
+                {
+                    case AsyncIteratorState.Allocated:
+                        hasEnumerator = false;
+                        state = AsyncIteratorState.Iterating;
+                        if (!appending)
+                        {
+                            current = item;
+                            return true;
+                        }
+
+                        goto case AsyncIteratorState.Iterating;
+
+                    case AsyncIteratorState.Iterating:
+                        if (!hasEnumerator)
+                        {
+                            GetSourceEnumerator();
+                            hasEnumerator = true;   
+                        }
+
+                        if (enumerator != null)
+                        {
+                            if (await LoadFromEnumerator(cancellationToken)
+                                .ConfigureAwait(false))
+                            {
+                                return true;
+                            }
+
+                            if (appending)
+                            {
+                                current = item;
+                                return true;
+                            }
+                        }
+
+                        break;
+                }
+
+                Dispose();
+                return false;
+            }
+
+            public override AppendPrepentAsyncIterator<TSource> Append(TSource element)
+            {
+                if (appending)
+                {
+                    return new AppendPrependNAsyncIterator<TSource>(source, null, new SingleLinkedNode<TSource>(item, element));
+                }
+
+                return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item), new SingleLinkedNode<TSource>(element));
+            }
+
+            public override AppendPrepentAsyncIterator<TSource> Prepend(TSource element)
+            {
+                if (appending)
+                {
+                    return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(element), new SingleLinkedNode<TSource>(item));
+                }
+
+                return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item, element), null);
+            }
+
+            public override async Task<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
+            {
+                var count = await GetCountAsync(onlyIfCheap: true, cancellationToken: cancellationToken).ConfigureAwait(false);
+                if (count == -1)
+                {
+                    return await AsyncEnumerableHelpers.ToArray(this, cancellationToken).ConfigureAwait(false);
+                }
+
+                var array = new TSource[count];
+                int index;
+                if (appending)
+                {
+                    index = 0;
+                }
+                else
+                {
+                    array[0] = item;
+                    index = 1;
+                }
+
+                var sourceCollection = source as ICollection<TSource>;
+                if (sourceCollection != null)
+                {
+                    sourceCollection.CopyTo(array, index);
+                }
+                else
+                {
+                    using (var en = source.GetEnumerator())
+                    {
+                        while (await en.MoveNext(cancellationToken)
+                                       .ConfigureAwait(false))
+                        {
+                            array[index] = en.Current;
+                            ++index;
+                        }
+                    }
+                }
+
+                if (appending)
+                {
+                    array[array.Length - 1] = item;
+                }
+
+                return array;
+            }
+
+            public override async Task<List<TSource>> ToListAsync(CancellationToken cancellationToken)
+            {
+                var count = await GetCountAsync(onlyIfCheap: true, cancellationToken: cancellationToken).ConfigureAwait(false);
+                var list = count == -1 ? new List<TSource>() : new List<TSource>(count);
+
+                if (!appending)
+                {
+                    list.Add(item);
+                }
+
+
+                using (var en = source.GetEnumerator())
+                {
+                    while (await en.MoveNext(cancellationToken)
+                                   .ConfigureAwait(false))
+                    {
+                        list.Add(en.Current);
+                    }
+                }
+
+                if (appending)
+                {
+                    list.Add(item);
+                }
+
+                return list;
+            }
+
+            public override async Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
+            {
+                var listProv = source as IIListProvider<TSource>;
+                if (listProv != null)
+                {
+                    var count = await listProv.GetCountAsync(onlyIfCheap, cancellationToken).ConfigureAwait(false);
+                    return count == -1 ? -1 : count + 1;
+                }
+
+                return !onlyIfCheap || source is ICollection<TSource> ? await source.Count(cancellationToken).ConfigureAwait(false) + 1 : -1;
+            }
+        }
+
+        private sealed class SingleLinkedNode<TSource>
+        {
+            public SingleLinkedNode(TSource first, TSource second)
+            {
+                Linked = new SingleLinkedNode<TSource>(first);
+                Item = second;
+                Count = 2;
+            }
+
+            public SingleLinkedNode(TSource item)
+            {
+                Item = item;
+                Count = 1;
+            }
+
+            private SingleLinkedNode(SingleLinkedNode<TSource> linked, TSource item)
+            {
+                Debug.Assert(linked != null);
+                Linked = linked;
+                Item = item;
+                Count = linked.Count + 1;
+            }
+
+            public TSource Item { get; }
+
+            public SingleLinkedNode<TSource> Linked { get; }
+
+            public int Count { get; }
+
+            public SingleLinkedNode<TSource> Add(TSource item) => new SingleLinkedNode<TSource>(this, item);
+
+            public IEnumerator<TSource> GetEnumerator()
+            {
+                var array = new TSource[Count];
+                var index = Count;
+                for (var n = this; n != null; n = n.Linked)
+                {
+                    --index;
+                    array[index] = n.Item;
+                }
+
+                Debug.Assert(index == 0);
+                return ((IEnumerable<TSource>)array).GetEnumerator();
+            }
+        }
+
+        private sealed class AppendPrependNAsyncIterator<TSource> : AppendPrepentAsyncIterator<TSource>
+        {
+            private readonly SingleLinkedNode<TSource> prepended;
+            private readonly SingleLinkedNode<TSource> appended;
+
+            private SingleLinkedNode<TSource> node;
+
+            public AppendPrependNAsyncIterator(IAsyncEnumerable<TSource> source, SingleLinkedNode<TSource> prepended, SingleLinkedNode<TSource> appended)
+                : base(source)
+            {
+                Debug.Assert(prepended != null || appended != null);
+
+                this.prepended = prepended;
+                this.appended = appended;
+            }
+
+            public override AsyncIterator<TSource> Clone()
+            {
+                return new AppendPrependNAsyncIterator<TSource>(source, prepended, appended);
+            }
+
+            int mode;
+            IEnumerator<TSource> appendedEnumerator;
+
+            public override void Dispose()
+            {
+                if (appendedEnumerator != null)
+                {
+                    appendedEnumerator.Dispose();
+                    appendedEnumerator = null;
+                }
+
+                base.Dispose();
+            }
+
+            protected override async Task<bool> MoveNextCore(CancellationToken cancellationToken)
+            {
+                switch (state)
+                {
+                    case AsyncIteratorState.Allocated:
+                        mode = 1;
+                        state = AsyncIteratorState.Iterating; 
+                        goto case AsyncIteratorState.Iterating;
+
+                    case AsyncIteratorState.Iterating:
+                        switch (mode)
+                        {
+                            case 1:
+                                node = prepended;
+                                mode = 2;
+                                goto case 2;
+
+                            case 2:
+                                if (node != null)
+                                {
+                                    current = node.Item;
+                                    node = node.Linked;
+                                    return true;
+                                }
+
+                                GetSourceEnumerator();
+                                mode = 3;
+                                goto case 3;
+
+                            case 3:
+                                if (await LoadFromEnumerator(cancellationToken)
+                                        .ConfigureAwait(false))
+                                {
+                                    return true;
+                                }
+
+                                if (appended != null)
+                                {
+                                    appendedEnumerator = appended.GetEnumerator();
+                                    mode = 4;
+                                    goto case 4;
+                                }
+
+                                break;
+                                
+
+                            case 4:
+                                if (appendedEnumerator.MoveNext())
+                                {
+                                    current = appendedEnumerator.Current;
+                                    return true;
+                                }
+                                break;
+                        }
+
+                        break;
+                }
+
+                Dispose();
+                return false;
+            }
+
+            public override AppendPrepentAsyncIterator<TSource> Append(TSource item)
+            {
+                return new AppendPrependNAsyncIterator<TSource>(source, prepended, appended != null ? appended.Add(item) : new SingleLinkedNode<TSource>(item));
+            }
+
+            public override AppendPrepentAsyncIterator<TSource> Prepend(TSource item)
+            {
+                return new AppendPrependNAsyncIterator<TSource>(source, prepended != null ? prepended.Add(item) : new SingleLinkedNode<TSource>(item), appended);
+            }
+
+            public override async Task<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
+            {
+                var count = await GetCountAsync(onlyIfCheap: true, cancellationToken: cancellationToken).ConfigureAwait(false);
+                if (count == -1)
+                {
+                    return await AsyncEnumerableHelpers.ToArray(this, cancellationToken).ConfigureAwait(false);
+                }
+
+                var array = new TSource[count];
+                var index = 0;
+                for (var n = prepended; n != null; n = n.Linked)
+                {
+                    array[index] = n.Item;
+                    ++index;
+                }
+
+                var sourceCollection = source as ICollection<TSource>;
+                if (sourceCollection != null)
+                {
+                    sourceCollection.CopyTo(array, index);
+                }
+                else
+                {
+                    using (var en = source.GetEnumerator())
+                    {
+                        while (await en.MoveNext(cancellationToken)
+                                       .ConfigureAwait(false))
+                        {
+                            array[index] = en.Current;
+                            ++index;
+                        }
+                    }
+                }
+
+                index = array.Length;
+                for (var n = appended; n != null; n = n.Linked)
+                {
+                    --index;
+                    array[index] = n.Item;
+                }
+
+                return array;
+            }
+
+            public override async Task<List<TSource>> ToListAsync(CancellationToken cancellationToken)
+            {
+                var count = await GetCountAsync(onlyIfCheap: true, cancellationToken: cancellationToken).ConfigureAwait(false);
+                var list = count == -1 ? new List<TSource>() : new List<TSource>(count);
+                for (var n = prepended; n != null; n = n.Linked)
+                {
+                    list.Add(n.Item);
+                }
+
+                using (var en = source.GetEnumerator())
+                {
+                    while (await en.MoveNext(cancellationToken)
+                                   .ConfigureAwait(false))
+                    {
+                        list.Add(en.Current);
+                    }
+                }
+                
+                if (appended != null)
+                {
+
+                    using (var en = appended.GetEnumerator())
+                    {
+                        while (en.MoveNext())
+                        {
+                            list.Add(en.Current);
+                        }
+                    }
+                }
+
+                return list;
+            }
+
+            public override async Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
+            {
+                var listProv = source as IIListProvider<TSource>;
+                if (listProv != null)
+                {
+                    var count = await listProv.GetCountAsync(onlyIfCheap, cancellationToken).ConfigureAwait(false);
+                    return count == -1 ? -1 : count + (appended == null ? 0 : appended.Count) + (prepended == null ? 0 : prepended.Count);
+                }
+
+                return !onlyIfCheap || source is ICollection<TSource> ? await source.Count(cancellationToken).ConfigureAwait(false) + (appended == null ? 0 : appended.Count) + (prepended == null ? 0 : prepended.Count) : -1;
+            }
+        }
+    }
+}

+ 592 - 0
Ix.NET/Source/Tests/AppendPrependTests.cs

@@ -0,0 +1,592 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public partial class AsyncTests
+    {
+        [Fact]
+        public void Append1()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4);
+
+            var e = res.GetEnumerator();
+
+            HasNext(e, 1);
+            HasNext(e, 2);
+            HasNext(e, 3);
+            HasNext(e, 4);
+            NoNext(e);
+        }
+
+        [Fact]
+        public async Task Append2()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4);
+
+            var a = new[] {1, 2, 3, 4};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task Append3()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+            var res = xs.Append(4);
+            var a = new List<int>
+            {
+                1,
+                2,
+                3,
+                4
+            };
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task Append4()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4);
+            Assert.Equal(4, await res.Count());
+        }
+
+        [Fact]
+        public async Task Append5()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Append(4);
+
+            var a = new[] {1, 2, 3, 4};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task Append6()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Append(4);
+            Assert.Equal(4, await res.Count());
+        }
+
+        [Fact]
+        public async Task Append7()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+            var res = xs.Append(4);
+            var a = new List<int>
+            {
+                1,
+                2,
+                3,
+                4
+            };
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+
+        [Fact]
+        public void AppendN1()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+
+            var e = res.GetEnumerator();
+
+            HasNext(e, 1);
+            HasNext(e, 2);
+            HasNext(e, 3);
+            HasNext(e, 4);
+            HasNext(e, 5);
+            HasNext(e, 6);
+            NoNext(e);
+        }
+
+        [Fact]
+        public async Task AppendN2()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+
+            var a = new[] {1, 2, 3, 4, 5, 6};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendN3()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+
+            var a = new List<int>
+            {
+                1,
+                2,
+                3,
+                4,
+                5,
+                6
+            };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+
+        [Fact]
+        public async Task AppendN5()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+
+            var a = new[] {1, 2, 3, 4, 5, 6};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendN6()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+
+            var a = new List<int>
+            {
+                1,
+                2,
+                3,
+                4,
+                5,
+                6
+            };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendN7()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+            Assert.Equal(6, await res.Count());
+        }
+
+        [Fact]
+        public async Task AppenN4()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Append(4)
+                        .Append(5)
+                        .Append(6);
+            Assert.Equal(6, await res.Count());
+        }
+
+        [Fact]
+        public void Prepend1()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4);
+
+            var e = res.GetEnumerator();
+
+            HasNext(e, 4);
+            HasNext(e, 1);
+            HasNext(e, 2);
+            HasNext(e, 3);
+            NoNext(e);
+        }
+
+        [Fact]
+        public async Task Prepend2()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4);
+
+            var a = new[] {4, 1, 2, 3};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task Prepend3()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+            var res = xs.Prepend(4);
+            var a = new List<int>
+            {
+                4,
+                1,
+                2,
+                3
+            };
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+
+        [Fact]
+        public async Task Prepend4()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4);
+            Assert.Equal(4, await res.Count());
+        }
+
+
+        [Fact]
+        public async Task Prepend5()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4);
+
+            var a = new[] {4, 1, 2, 3};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task Prepend6()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+            var res = xs.Prepend(4);
+            var a = new List<int>
+            {
+                4,
+                1,
+                2,
+                3
+            };
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+
+        [Fact]
+        public async Task Prepend7()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4);
+            Assert.Equal(4, await res.Count());
+        }
+
+
+        [Fact]
+        public void PrependN1()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+
+            var e = res.GetEnumerator();
+
+            HasNext(e, 6);
+            HasNext(e, 5);
+            HasNext(e, 4);
+            HasNext(e, 1);
+            HasNext(e, 2);
+            HasNext(e, 3);
+            NoNext(e);
+        }
+
+        [Fact]
+        public async Task PrependN2()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+
+            var a = new[] {6, 5, 4, 1, 2, 3};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task PrependN3()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+
+            var a = new List<int>
+            {
+                6,
+                5,
+                4,
+                1,
+                2,
+                3
+            };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task PrependN4()
+        {
+            var xs = new[] {1, 2, 3}.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+            Assert.Equal(6, await res.Count());
+        }
+
+        [Fact]
+        public async Task PrependN5()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+
+            var a = new[] {6, 5, 4, 1, 2, 3};
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task PrependN6()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+
+            var a = new List<int>
+            {
+                6,
+                5,
+                4,
+                1,
+                2,
+                3
+            };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task PrependN7()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4)
+                        .Prepend(5)
+                        .Prepend(6);
+            Assert.Equal(6, await res.Count());
+        }
+
+
+        [Fact]
+        public void AppendPrepend1()
+        {
+            var xs = new[] { 1, 2, 3 }.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            var e = res.GetEnumerator();
+            
+
+            HasNext(e, 10);
+            HasNext(e, 9);
+            HasNext(e, 7);
+            HasNext(e, 4);
+            HasNext(e, 1);
+            HasNext(e, 2);
+            HasNext(e, 3);
+            HasNext(e, 5);
+            HasNext(e, 6);
+            HasNext(e, 8);
+            NoNext(e);
+        }
+
+        [Fact]
+        public async Task AppendPrepend2()
+        {
+            var xs = new[] { 1, 2, 3 }.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            var a = new[] { 10, 9, 7, 4, 1, 2, 3, 5, 6, 8 };
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendPrepend3()
+        {
+            var xs = new[] { 1, 2, 3 }.ToAsyncEnumerable();
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            var a = new List<int> { 10, 9, 7, 4, 1, 2, 3, 5, 6, 8 };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendPrepend4()
+        {
+            var xs = new[] { 1, 2, 3 }.ToAsyncEnumerable();
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            Assert.Equal(10, await res.Count());
+        }
+
+
+        [Fact]
+        public async Task AppendPrepend5()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            var a = new[] { 10, 9, 7, 4, 1, 2, 3, 5, 6, 8 };
+
+            var arr = await res.ToArray();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendPrepend6()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            var a = new List<int> { 10, 9, 7, 4, 1, 2, 3, 5, 6, 8 };
+
+            var arr = await res.ToList();
+            Assert.Equal(a, arr);
+        }
+
+        [Fact]
+        public async Task AppendPrepend7()
+        {
+            var xs = AsyncEnumerable.Range(1, 3)
+                                    .Where(i => true);
+
+            var res = xs.Prepend(4)
+                        .Append(5)
+                        .Append(6)
+                        .Prepend(7)
+                        .Append(8)
+                        .Prepend(9)
+                        .Prepend(10);
+
+            Assert.Equal(10, await res.Count());
+        }
+
+
+    }
+}