From 4f59ae1b7d1d4caabf4b3250945efc085016d909 Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 1 Mar 2024 23:46:00 +0900 Subject: [PATCH] Add Append/Prepend(IEnumerable), (Func), (TState, Func) --- src/R3/Operators/AppendPrepend.cs | 179 +++++++++++++++++- .../OperatorTests/ConcatAppendPrependTest.cs | 68 +++++++ 2 files changed, 246 insertions(+), 1 deletion(-) diff --git a/src/R3/Operators/AppendPrepend.cs b/src/R3/Operators/AppendPrepend.cs index 24e742e7..b6e08278 100644 --- a/src/R3/Operators/AppendPrepend.cs +++ b/src/R3/Operators/AppendPrepend.cs @@ -7,12 +7,41 @@ public static Observable Append(this Observable source, T value) return new AppendPrepend(source, value, append: true); } + public static Observable Append(this Observable source, IEnumerable values) + { + return new AppendPrependEnumerable(source, values, append: true); + } + + public static Observable Append(this Observable source, Func valueFactory) + { + return new AppendPrependFactory(source, valueFactory, append: true); + } + + public static Observable Append(this Observable source, TState state, Func valueFactory) + { + return new AppendPrependFactory(source, state, valueFactory, append: true); + } + public static Observable Prepend(this Observable source, T value) { return new AppendPrepend(source, value, append: false); } -} + public static Observable Prepend(this Observable source, IEnumerable values) + { + return new AppendPrependEnumerable(source, values, append: false); + } + + public static Observable Prepend(this Observable source, Func valueFactory) + { + return new AppendPrependFactory(source, valueFactory, append: false); + } + + public static Observable Prepend(this Observable source, TState state, Func valueFactory) + { + return new AppendPrependFactory(source, state, valueFactory, append: false); + } +} internal sealed class AppendPrepend(Observable source, T value, bool append) : Observable { @@ -53,3 +82,151 @@ protected override void OnCompletedCore(Result result) } } } + +internal sealed class AppendPrependEnumerable(Observable source, IEnumerable values, bool append) : Observable +{ + protected override IDisposable SubscribeCore(Observer observer) + { + if (!append) // prepend + { + if (values is T[] array) + { + foreach (var value in array) + { + observer.OnNext(value); + } + } + else + { + foreach (var value in values) + { + observer.OnNext(value); + } + } + + return source.Subscribe(observer.Wrap()); + } + + return source.Subscribe(new _Append(observer, values)); + } + + sealed class _Append(Observer observer, IEnumerable values) : Observer + { + protected override void OnNextCore(T value) + { + observer.OnNext(value); + } + + protected override void OnErrorResumeCore(Exception error) + { + observer.OnErrorResume(error); + } + + protected override void OnCompletedCore(Result result) + { + if (result.IsFailure) + { + observer.OnCompleted(result); + } + else + { + if (values is T[] array) + { + foreach (var value in array) + { + observer.OnNext(value); + } + } + else + { + foreach (var value in values) + { + observer.OnNext(value); + } + } + + observer.OnCompleted(); + } + } + } +} + +internal sealed class AppendPrependFactory(Observable source, Func valueFactory, bool append) : Observable +{ + protected override IDisposable SubscribeCore(Observer observer) + { + if (!append) // prepend + { + observer.OnNext(valueFactory()); + return source.Subscribe(observer.Wrap()); + } + + return source.Subscribe(new _Append(observer, valueFactory)); + } + + sealed class _Append(Observer observer, Func valueFactory) : Observer + { + protected override void OnNextCore(T value) + { + observer.OnNext(value); + } + + protected override void OnErrorResumeCore(Exception error) + { + observer.OnErrorResume(error); + } + + protected override void OnCompletedCore(Result result) + { + if (result.IsFailure) + { + observer.OnCompleted(result); + } + else + { + observer.OnNext(valueFactory()); + observer.OnCompleted(); + } + } + } +} + +internal sealed class AppendPrependFactory(Observable source, TState state, Func valueFactory, bool append) : Observable +{ + protected override IDisposable SubscribeCore(Observer observer) + { + if (!append) // prepend + { + observer.OnNext(valueFactory(state)); + return source.Subscribe(observer.Wrap()); + } + + return source.Subscribe(new _Append(observer, state, valueFactory)); + } + + sealed class _Append(Observer observer, TState state, Func valueFactory) : Observer + { + protected override void OnNextCore(T value) + { + observer.OnNext(value); + } + + protected override void OnErrorResumeCore(Exception error) + { + observer.OnErrorResume(error); + } + + protected override void OnCompletedCore(Result result) + { + if (result.IsFailure) + { + observer.OnCompleted(result); + } + else + { + observer.OnNext(valueFactory(state)); + observer.OnCompleted(); + } + } + } +} diff --git a/tests/R3.Tests/OperatorTests/ConcatAppendPrependTest.cs b/tests/R3.Tests/OperatorTests/ConcatAppendPrependTest.cs index 78f46fa4..1def5a86 100644 --- a/tests/R3.Tests/OperatorTests/ConcatAppendPrependTest.cs +++ b/tests/R3.Tests/OperatorTests/ConcatAppendPrependTest.cs @@ -180,4 +180,72 @@ public void ConcatNestedSources_Empty() list.AssertIsCompleted(); list.AssertEqual([]); } + + // Prepend factory + [Fact] + public void PrependFactory() + { + { + using var list = Observable.Range(1, 3).Prepend(() => 10).ToLiveList(); + list.AssertEqual([10, 1, 2, 3]); + } + // with state + { + var o = new { V = 20 }; + using var list = Observable.Range(1, 3).Prepend(o, static x => x.V).ToLiveList(); + list.AssertEqual([20, 1, 2, 3]); + } + } + + [Fact] + public void PrependEnumerable() + { + // Array + { + using var list = Observable.Range(1, 3).Prepend([10, 11, 12]).ToLiveList(); + list.AssertEqual([10, 11, 12, 1, 2, 3]); + } + // Pure Enumerable + { + using var list = Observable.Range(1, 3).Prepend(Iterate()).ToLiveList(); + list.AssertEqual([100, 200, 300, 1, 2, 3]); + } + } + + [Fact] + public void AppendFactory() + { + { + using var list = Observable.Range(1, 3).Append(() => 10).ToLiveList(); + list.AssertEqual([1, 2, 3, 10]); + } + // with state + { + var o = new { V = 20 }; + using var list = Observable.Range(1, 3).Append(o, static x => x.V).ToLiveList(); + list.AssertEqual([1, 2, 3, 20]); + } + } + + [Fact] + public void AppendEnumerable() + { + // Array + { + using var list = Observable.Range(1, 3).Append([10, 11, 12]).ToLiveList(); + list.AssertEqual([1, 2, 3, 10, 11, 12]); + } + // Pure Enumerable + { + using var list = Observable.Range(1, 3).Append(Iterate()).ToLiveList(); + list.AssertEqual([1, 2, 3, 100, 200, 300]); + } + } + + static IEnumerable Iterate() + { + yield return 100; + yield return 200; + yield return 300; + } }