├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Reactor.Core.Test ├── AllTest.cs ├── AnyTest.cs ├── BufferBoundaryTest.cs ├── BufferTest.cs ├── ConcatMapTest.cs ├── DefaultIfEmptyTest.cs ├── DelaySubscriptionTest.cs ├── DirectProcessorTest.cs ├── FilterTest.cs ├── FlatMapTest.cs ├── FlattenEnumerableTest.cs ├── FromEnumerable.cs ├── GroupByTest.cs ├── HasElementsTest.cs ├── JustTest.cs ├── MapNotificationTest.cs ├── MaterializeTest.cs ├── OnBackpressureBufferTest.cs ├── OnBackpressureLatestTest.cs ├── OnErrorResumeWith.cs ├── ParallelTest.cs ├── ProcessTest.cs ├── Properties │ └── AssemblyInfo.cs ├── PublishOnTest.cs ├── PublishProcessorTest.cs ├── PublishSelectorTest.cs ├── Reactor.Core.Test.csproj ├── ReduceTest.cs ├── SampleTest.cs ├── ScanTest.cs ├── SingleTest.cs ├── SkipLastTest.cs ├── SkipTest.cs ├── SkipUntilTest.cs ├── SkipWhileTest.cs ├── SubscribeOnTest.cs ├── SwitchIfEmptyTest.cs ├── SwitchMapTest.cs ├── TakeLastTest.cs ├── TakeTest.cs ├── TakeUntilPredicateTest.cs ├── TakeUntilTest.cs ├── TakeWhileTest.cs ├── ThenManyTest.cs ├── ThenTest.cs ├── TimeoutTest.cs ├── ToEnumerableTest.cs ├── UnicastProcessorTest.cs ├── UsingTest.cs ├── WithLatestFromTest.cs ├── ZipEnumerableTest.cs ├── ZipTest.cs ├── app.config ├── packages.config └── tck │ ├── ConcatTckTest.cs │ └── FluxPublisherVerification.cs ├── Reactor.Core ├── BackpressureHandling.cs ├── ConcatErrorMode.cs ├── ConnectableFlux.cs ├── DirectProcessor.cs ├── ExceptionHelper.cs ├── Flux.cs ├── IConnectableFlux.cs ├── IFlux.cs ├── IFluxEmitter.cs ├── IFluxProcessor.cs ├── IGroupedFlux.cs ├── IMono.cs ├── IMonoEmitter.cs ├── IOrderedItem.cs ├── IParallelFlux.cs ├── IReactiveStreams.cs ├── ISignal.cs ├── ISignalEmitter.cs ├── Mono.cs ├── ParallelFlux.cs ├── Properties │ └── AssemblyInfo.cs ├── PublishProcessor.cs ├── Reactor.Core.csproj ├── Scheduler.cs ├── Timed.cs ├── UnicastProcessor.cs ├── Void.cs ├── flow │ ├── FuseableHelper.cs │ ├── ICallable.cs │ ├── IConditionalSubscriber.cs │ ├── IQueue.cs │ └── IQueueSubscription.cs ├── packages.config ├── parallel │ ├── ParallelFromPublishers.cs │ ├── ParallelGroups.cs │ ├── ParallelOrderedFilter.cs │ ├── ParallelOrderedFork.cs │ ├── ParallelOrderedJoin.cs │ ├── ParallelOrderedMap.cs │ ├── ParallelOrderedRunOn.cs │ ├── ParallelReduce.cs │ ├── ParallelReduceFull.cs │ ├── ParallelSortedJoin.cs │ ├── ParallelUnorderedFilter.cs │ ├── ParallelUnorderedFork.cs │ ├── ParallelUnorderedJoin.cs │ ├── ParallelUnorderedMap.cs │ └── ParallelUnorderedRunOn.cs ├── publisher │ ├── MonoPublishOn.cs │ ├── PublisherAction.cs │ ├── PublisherAll.cs │ ├── PublisherAmb.cs │ ├── PublisherAny.cs │ ├── PublisherArray.cs │ ├── PublisherAsEnumerable.cs │ ├── PublisherAsObservable.cs │ ├── PublisherBufferBoundary.cs │ ├── PublisherBufferOpenClose.cs │ ├── PublisherBufferSize.cs │ ├── PublisherBufferTimeAndSize.cs │ ├── PublisherCache.cs │ ├── PublisherCallableXMap.cs │ ├── PublisherCollect.cs │ ├── PublisherCombineLatest.cs │ ├── PublisherConcatArray.cs │ ├── PublisherConcatEnumerable.cs │ ├── PublisherConcatMap.cs │ ├── PublisherCount.cs │ ├── PublisherCreate.cs │ ├── PublisherDefaultIfEmpty.cs │ ├── PublisherDefer.cs │ ├── PublisherDelay.cs │ ├── PublisherDelaySubscription.cs │ ├── PublisherDematerialize.cs │ ├── PublisherDistinct.cs │ ├── PublisherDistinctUntilChanged.cs │ ├── PublisherElapsed.cs │ ├── PublisherElementAt.cs │ ├── PublisherEmpty.cs │ ├── PublisherEnumerable.cs │ ├── PublisherError.cs │ ├── PublisherFilter.cs │ ├── PublisherFirstOrEmpty.cs │ ├── PublisherFlatMap.cs │ ├── PublisherFlattenEnumerable.cs │ ├── PublisherFromObservable.cs │ ├── PublisherFromTask.cs │ ├── PublisherFunc.cs │ ├── PublisherGenerate.cs │ ├── PublisherGroupBy.cs │ ├── PublisherHasElements.cs │ ├── PublisherHide.cs │ ├── PublisherIgnoreBoth.cs │ ├── PublisherIgnoreElements.cs │ ├── PublisherInterval.cs │ ├── PublisherJust.cs │ ├── PublisherLast.cs │ ├── PublisherMap.cs │ ├── PublisherMapError.cs │ ├── PublisherMapNotification.cs │ ├── PublisherMaterialize.cs │ ├── PublisherMergeArray.cs │ ├── PublisherNever.cs │ ├── PublisherOnBackpressureBuffer.cs │ ├── PublisherOnBackpressureDrop.cs │ ├── PublisherOnBackpressureLatest.cs │ ├── PublisherOnErrorResumeWith.cs │ ├── PublisherOnTerminateDetach.cs │ ├── PublisherPeek.cs │ ├── PublisherProcess.cs │ ├── PublisherPublishOn.cs │ ├── PublisherPublishSelector.cs │ ├── PublisherRange.cs │ ├── PublisherReduce.cs │ ├── PublisherReduceWith.cs │ ├── PublisherSample.cs │ ├── PublisherScan.cs │ ├── PublisherScanWith.cs │ ├── PublisherSingle.cs │ ├── PublisherSkip.cs │ ├── PublisherSkipLast.cs │ ├── PublisherSkipUntil.cs │ ├── PublisherSkipWhile.cs │ ├── PublisherSubscribeOn.cs │ ├── PublisherSwitchIfEmpty.cs │ ├── PublisherSwitchMap.cs │ ├── PublisherTake.cs │ ├── PublisherTakeLast.cs │ ├── PublisherTakeLastOne.cs │ ├── PublisherTakeUntil.cs │ ├── PublisherTakeUntilPredicate.cs │ ├── PublisherTakeWhile.cs │ ├── PublisherTck.cs │ ├── PublisherThen.cs │ ├── PublisherTimeout.cs │ ├── PublisherTimer.cs │ ├── PublisherUsing.cs │ ├── PublisherWithLatestFrom.cs │ ├── PublisherWrap.cs │ ├── PublisherZip.cs │ └── PublisherZipEnumerable.cs ├── scheduler │ ├── DefaultScheduler.cs │ └── ImmediateScheduler.cs ├── subscriber │ ├── BasicConditionalSubscriber.cs │ ├── BasicFuseableConditionalSubscriber.cs │ ├── BasicFuseableSubscriber.cs │ ├── BasicPostCompleteSubscriber.cs │ ├── BasicSubscriber.cs │ ├── BlockingFirstSubscriber.cs │ ├── BlockingLastSubscriber.cs │ ├── CallbackSubscriber.cs │ ├── DeferredScalarSubscriber.cs │ ├── TaskCompleteSubscriber.cs │ ├── TaskFirstSubscriber.cs │ ├── TaskLastSubscriber.cs │ └── TestSubscriber.cs ├── subscription │ ├── BasicRejectingSubscription.cs │ ├── DeferredScalarSubscription.cs │ ├── EmptySubscription.cs │ ├── NeverSubscription.cs │ ├── ScalarSubscription.cs │ ├── SubscriptionArbiterStruct.cs │ └── SubscriptionHelper.cs └── util │ ├── ArrayQueue.cs │ ├── BackpressureHelper.cs │ ├── DisposableHelper.cs │ ├── FalseSharing.cs │ ├── HalfSerializerStruct.cs │ ├── IndexedMultipleDisposable.cs │ ├── MultiSourceHelper.cs │ ├── MultipleDisposable.cs │ ├── ObjectHelper.cs │ ├── OrderedItem.cs │ ├── QueueDrainHelper.cs │ ├── QueueHelper.cs │ ├── SpscArrayQueue.cs │ ├── SpscFreelistTracker.cs │ ├── SpscLinkedArrayQueue.cs │ ├── SpscOneQueue.cs │ └── TrackingArray.cs └── reactor-core-dotnet.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | solution: reactor-core-dotnet.sln 3 | install: 4 | - nuget restore reactor-core-dotnet.sln 5 | - nuget install NUnit.Runners -Version 3.4.0 -OutputDirectory testrunner 6 | script: 7 | - xbuild /p:Configuration=Release /p:TargetFrameworkVersion="v4.5" reactor-core-dotnet.sln 8 | - mono ./testrunner/NUnit.ConsoleRunner.3.4.0/tools/nunit3-console.exe ./Reactor.Core.Test/bin/Release/Reactor.Core.Test.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reactor-core-dotnet is no longer actively maintained by VMware, Inc. 2 | 3 | # reactor-core-dotnet 4 | 5 | Fluent reactive programming library for C# on top of Reactive-Streams, mirroring the Reactor-Core for JVM. 6 | 7 | 8 | 9 | NuGet: https://www.nuget.org/packages/Reactor.Core/ 10 | 11 | Install: 12 | 13 | ``` 14 | PM> Install-Package Reactor.Core 15 | ``` 16 | -------------------------------------------------------------------------------- /Reactor.Core.Test/AllTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class AllTest 9 | { 10 | [Test] 11 | public void All_Normal() 12 | { 13 | Flux.Range(1, 5).All(v => v < 6).Test().AssertResult(true); 14 | } 15 | 16 | [Test] 17 | public void All_Empty() 18 | { 19 | Flux.Empty().All(v => v == 3).Test().AssertResult(true); 20 | } 21 | 22 | [Test] 23 | public void All_Normal_2() 24 | { 25 | Flux.Range(1, 5).All(v => v < 5).Test().AssertResult(false); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Reactor.Core.Test/AnyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class AnyTest 9 | { 10 | [Test] 11 | public void Any_Normal() 12 | { 13 | Flux.Range(1, 5).Any(v => v == 3).Test().AssertResult(true); 14 | } 15 | 16 | [Test] 17 | public void Any_Empty() 18 | { 19 | Flux.Empty().Any(v => v == 3).Test().AssertResult(false); 20 | } 21 | 22 | [Test] 23 | public void Any_Normal_2() 24 | { 25 | Flux.Range(1, 5).Any(v => v == 7).Test().AssertResult(false); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Reactor.Core.Test/BufferBoundaryTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class BufferBoundaryTest 10 | { 11 | [Test] 12 | public void BufferBoundary_Normal() 13 | { 14 | var other = new DirectProcessor(); 15 | 16 | var main = new DirectProcessor(); 17 | 18 | var ts = main.Buffer(other).Test(); 19 | 20 | main.OnNext(1, 2, 3); 21 | 22 | other.OnNext(1); 23 | 24 | main.OnNext(4, 5); 25 | 26 | other.OnNext(2, 3); 27 | 28 | main.OnNext(6); 29 | main.OnComplete(); 30 | 31 | Assert.False(main.HasSubscribers); 32 | Assert.False(other.HasSubscribers); 33 | 34 | ts.AssertResult( 35 | new List(new[] { 1, 2, 3 }), 36 | new List(new[] { 4, 5, }), 37 | new List(new[] { 6 }) 38 | ); 39 | } 40 | 41 | [Test] 42 | public void BufferBoundary_Other_Completes_Immediately() 43 | { 44 | var main = new DirectProcessor(); 45 | 46 | var ts = main.Buffer(Flux.Empty()).Test(); 47 | 48 | ts.AssertSubscribed() 49 | .AssertResult(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Reactor.Core.Test/BufferTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class BufferTest 10 | { 11 | [Test] 12 | public void Buffer_Exact() 13 | { 14 | Flux.Range(1, 5).Buffer(2).Test().AssertResult( 15 | new List(new[] { 1, 2 }), 16 | new List(new[] { 3, 4 }), 17 | new List(new[] { 5 }) 18 | ); 19 | } 20 | 21 | [Test] 22 | public void Buffer_Skip() 23 | { 24 | Flux.Range(1, 5).Buffer(2, 3).Test().AssertResult( 25 | new List(new[] { 1, 2 }), 26 | new List(new[] { 4, 5 }) 27 | ); 28 | } 29 | 30 | [Test] 31 | public void Buffer_Overlap() 32 | { 33 | Flux.Range(1, 5).Buffer(2, 1).Test().AssertResult( 34 | new List(new[] { 1, 2 }), 35 | new List(new[] { 2, 3 }), 36 | new List(new[] { 3, 4 }), 37 | new List(new[] { 4, 5 }), 38 | new List(new[] { 5 }) 39 | ); 40 | } 41 | 42 | [Test] 43 | public void Buffer_Overlap_Backpressured() 44 | { 45 | var ts = Flux.Range(1, 5).Buffer(2, 1).Test(2); 46 | 47 | ts.AssertValues( 48 | new List(new[] { 1, 2 }), 49 | new List(new[] { 2, 3 }) 50 | ); 51 | 52 | ts.Request(1); 53 | 54 | ts.AssertValues( 55 | new List(new[] { 1, 2 }), 56 | new List(new[] { 2, 3 }), 57 | new List(new[] { 3, 4 }) 58 | ); 59 | 60 | ts.Request(1); 61 | 62 | ts.AssertValues( 63 | new List(new[] { 1, 2 }), 64 | new List(new[] { 2, 3 }), 65 | new List(new[] { 3, 4 }), 66 | new List(new[] { 4, 5 }) 67 | ); 68 | 69 | ts.Request(1); 70 | 71 | ts.AssertResult( 72 | new List(new[] { 1, 2 }), 73 | new List(new[] { 2, 3 }), 74 | new List(new[] { 3, 4 }), 75 | new List(new[] { 4, 5 }), 76 | new List(new[] { 5 }) 77 | ); 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Reactor.Core.Test/DefaultIfEmptyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class DefaultIfEmptyTest 9 | { 10 | [Test] 11 | public void DefaultIfEmpty_Non_Empty() 12 | { 13 | Flux.Just(1).DefaultIfEmpty(0).Test().AssertResult(1); 14 | } 15 | 16 | [Test] 17 | public void DefaultIfEmpty_Empty() 18 | { 19 | Flux.Empty().DefaultIfEmpty(0).Test().AssertResult(0); 20 | } 21 | 22 | [Test] 23 | public void DefaultIfEmpty_Empty_Backpressured() 24 | { 25 | var ts = Flux.Empty().DefaultIfEmpty(0).Test(0); 26 | 27 | ts.AssertNoValues(); 28 | 29 | ts.Request(1); 30 | 31 | ts.AssertResult(0); 32 | } 33 | 34 | [Test] 35 | public void DefaultIfEmpty_Non_Empty_Backpressured() 36 | { 37 | var ts = Flux.Range(1, 5).DefaultIfEmpty(0).Test(0); 38 | 39 | ts.AssertNoValues(); 40 | 41 | ts.Request(1); 42 | 43 | ts.AssertValues(1); 44 | 45 | ts.Request(2); 46 | 47 | ts.AssertValues(1, 2, 3); 48 | 49 | ts.Request(2); 50 | 51 | ts.AssertResult(1, 2, 3, 4, 5); 52 | } 53 | 54 | [Test] 55 | public void DefaultIfEmpty_Non_Empty_Conditional() 56 | { 57 | Flux.Just(1).DefaultIfEmpty(0).Filter(v => true).Test().AssertResult(1); 58 | } 59 | 60 | [Test] 61 | public void DefaultIfEmpty_Empty_Conditional() 62 | { 63 | Flux.Empty().DefaultIfEmpty(0).Filter(v => true).Test().AssertResult(0); 64 | } 65 | 66 | [Test] 67 | public void DefaultIfEmpty_Empty_Backpressured_Conditional() 68 | { 69 | var ts = Flux.Empty().DefaultIfEmpty(0).Filter(v => true).Test(0); 70 | 71 | ts.AssertNoValues(); 72 | 73 | ts.Request(1); 74 | 75 | ts.AssertResult(0); 76 | } 77 | 78 | [Test] 79 | public void DefaultIfEmpty_Non_Empty_Backpressured_Conditional() 80 | { 81 | var ts = Flux.Range(1, 5).DefaultIfEmpty(0).Filter(v => true).Test(0); 82 | 83 | ts.AssertNoValues(); 84 | 85 | ts.Request(1); 86 | 87 | ts.AssertValues(1); 88 | 89 | ts.Request(2); 90 | 91 | ts.AssertValues(1, 2, 3); 92 | 93 | ts.Request(2); 94 | 95 | ts.AssertResult(1, 2, 3, 4, 5); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Reactor.Core.Test/DelaySubscriptionTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class DelaySubscriptionTest 9 | { 10 | [Test] 11 | public void DelaySubscription_Just() 12 | { 13 | Flux.Range(1, 5).DelaySubscription(Flux.Just(1)).Test().AssertResult(1, 2, 3, 4, 5); 14 | } 15 | 16 | 17 | [Test] 18 | public void DelaySubscription_Range() 19 | { 20 | Flux.Range(1, 5).DelaySubscription(Flux.Range(1, 2)).Test().AssertResult(1, 2, 3, 4, 5); 21 | } 22 | 23 | [Test] 24 | public void DelaySubscription_Empty() 25 | { 26 | Flux.Range(1, 5).DelaySubscription(Flux.Empty()).Test().AssertResult(1, 2, 3, 4, 5); 27 | } 28 | 29 | [Test] 30 | public void DelaySubscription_Just_Conditional() 31 | { 32 | Flux.Range(1, 5).DelaySubscription(Flux.Just(1)).Filter(v => true).Test().AssertResult(1, 2, 3, 4, 5); 33 | } 34 | 35 | 36 | [Test] 37 | public void DelaySubscription_Range_Conditional() 38 | { 39 | Flux.Range(1, 5).DelaySubscription(Flux.Range(1, 2)).Filter(v => true).Test().AssertResult(1, 2, 3, 4, 5); 40 | } 41 | 42 | [Test] 43 | public void DelaySubscription_Empty_Conditional() 44 | { 45 | Flux.Range(1, 5).DelaySubscription(Flux.Empty()).Filter(v => true).Test().AssertResult(1, 2, 3, 4, 5); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Reactor.Core.Test/DirectProcessorTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class DirectProcessorTest 9 | { 10 | [Test] 11 | public void DirectProcessor_Normal() 12 | { 13 | DirectProcessor dp = new DirectProcessor(); 14 | 15 | var ts = dp.Test(); 16 | 17 | ts.AssertSubscribed() 18 | .AssertNoEvents(); 19 | 20 | dp.OnNext(1); 21 | dp.OnNext(2); 22 | dp.OnComplete(); 23 | 24 | Assert.IsFalse(dp.HasSubscribers); 25 | 26 | ts.AssertResult(1, 2); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Reactor.Core.Test/FilterTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class FilterTest 9 | { 10 | [Test] 11 | public void Filter_Normal() 12 | { 13 | Flux.Range(1, 5).Filter(v => (v & 1) == 0).Test().AssertResult(2, 4); 14 | } 15 | 16 | [Test] 17 | public void Filter_Error() 18 | { 19 | Flux.Error(new Exception("Forced failure")) 20 | .Filter(v => (v & 1) == 0).Test() 21 | .AssertNoValues().AssertErrorMessage("Forced failure").AssertNotComplete(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Reactor.Core.Test/FlatMapTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class FlatMapTest 10 | { 11 | [Test] 12 | public void FlatMap_Normal() 13 | { 14 | Flux.Range(1, 5) 15 | .FlatMap(v => Flux.Range(v, 2)) 16 | .Test().AssertResult(1, 2, 2, 3, 3, 4, 4, 5, 5, 6); 17 | } 18 | 19 | [Test] 20 | public void FlatMap_Error() 21 | { 22 | Flux.Error(new Exception("Forced failure")) 23 | .FlatMap(v => Flux.Just(1)) 24 | .Test() 25 | .AssertNoValues().AssertErrorMessage("Forced failure").AssertNotComplete(); 26 | } 27 | 28 | [Test] 29 | public void FlatMap_Mono_Enumerable() 30 | { 31 | Mono.Just(1).FlatMap(v => new List(new[] { 1, 2, 3, 4, 5 })) 32 | .Test().AssertResult(1, 2, 3, 4, 5); 33 | } 34 | 35 | [Test] 36 | public void FlatMap_Mono_Mono() 37 | { 38 | Mono.Just(1).FlatMap(v => Mono.Just(v + 1)) 39 | .Test().AssertResult(2); 40 | } 41 | 42 | [Test] 43 | public void FlatMap_Mono_Publisher() 44 | { 45 | Mono.Just(1).FlatMap(v => Flux.Range(v, 2)) 46 | .Test().AssertResult(1, 2); 47 | } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Reactor.Core.Test/FlattenEnumerableTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class FlattenEnumerableTest 10 | { 11 | [Test] 12 | public void FlattenEnumerable_Normal() 13 | { 14 | Flux.From( 15 | new List(new[] { 1, 2, 3 }), 16 | new List(), 17 | new List(new[] { 5 }), 18 | new List(new[] { 6, 7 }) 19 | ).ConcatMap(v => v) 20 | .Test() 21 | .AssertResult(1, 2, 3, 5, 6, 7); 22 | } 23 | 24 | [Test] 25 | public void FlattenEnumerable_Normal_Backpressure() 26 | { 27 | var ts = Flux.From( 28 | new List(new[] { 1, 2, 3 }), 29 | new List(), 30 | new List(new[] { 5 }), 31 | new List(new[] { 6, 7 }) 32 | ).ConcatMap(v => v) 33 | .Test(0); 34 | 35 | ts.AssertNoValues(); 36 | 37 | ts.Request(2); 38 | 39 | ts.AssertValues(1, 2); 40 | 41 | ts.Request(2); 42 | 43 | ts.AssertValues(1, 2, 3, 5); 44 | 45 | ts.Request(2); 46 | 47 | ts.AssertResult(1, 2, 3, 5, 6, 7); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Reactor.Core.Test/FromEnumerable.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class FromEnumerableTest 10 | { 11 | [Test] 12 | public void FromEnumerable_Normal() 13 | { 14 | IEnumerable en = new List(new int[] { 1, 2, 3, 4, 5 }); 15 | Flux.From(en) 16 | .Test().AssertResult(1, 2, 3, 4, 5); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Reactor.Core.Test/GroupByTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using Reactor.Core; 4 | using System.Collections.Generic; 5 | 6 | namespace Reactor.Core.Test 7 | { 8 | [TestFixture] 9 | [Timeout(30000)] 10 | public class GroupByTest 11 | { 12 | [Test] 13 | public void GroupBy_Normal() 14 | { 15 | Flux.Range(1, 10).GroupBy(k => k & 1) 16 | .FlatMap(g => g.CollectList()) 17 | .Test() 18 | .AssertResult( 19 | new List(new [] { 1, 3, 5, 7, 9 }), 20 | new List(new[] { 2, 4, 6, 8, 10 }) 21 | ); 22 | } 23 | [Test] 24 | public void GroupBy_2_of_3_Groups() 25 | { 26 | Flux.Range(1, 10).GroupBy(k => k % 3) 27 | .Take(2) 28 | .FlatMap(g => g.CollectList()) 29 | .Test() 30 | .AssertResult( 31 | new List(new[] { 1, 4, 7, 10 }), 32 | new List(new[] { 2, 5, 8 }) 33 | ); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Reactor.Core.Test/HasElementsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class HasElementsTest 9 | { 10 | [Test] 11 | public void HasElements_Normal() 12 | { 13 | Flux.Range(1, 5).HasElements().Test().AssertResult(true); 14 | } 15 | 16 | [Test] 17 | public void HasElements_Empty() 18 | { 19 | Flux.Empty().HasElements().Test().AssertResult(false); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Reactor.Core.Test/JustTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class JustTest 9 | { 10 | [Test] 11 | public void Just_Normal() 12 | { 13 | Assert.AreEqual(1, Flux.Just(1).BlockLast()); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Reactor.Core.Test/MapNotificationTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class MapNotificationTest 9 | { 10 | [Test] 11 | public void MapNotification_Normal() 12 | { 13 | Flux.Range(1, 3).FlatMap(t => Flux.Range(t, 2), t => Flux.Just(100), () => Flux.Just(50)) 14 | .Test().AssertResult(1, 2, 2, 3, 3, 4, 50); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Reactor.Core.Test/MaterializeTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class MaterializeTest 9 | { 10 | [Test] 11 | public void Materialize_Normal() 12 | { 13 | Flux.Range(1, 5).Materialize() 14 | .Test().AssertValueCount(6).AssertComplete(); 15 | } 16 | 17 | [Test] 18 | public void Materialize_Dematerialize() 19 | { 20 | Flux.Range(1, 5).Materialize().Dematerialize() 21 | .Test().AssertResult(1, 2, 3, 4, 5); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Reactor.Core.Test/OnBackpressureBufferTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class OnBackpressureBufferTest 10 | { 11 | [Test] 12 | public void OnBackpressureBuffer_Normal() 13 | { 14 | Flux.Range(1, 10).OnBackpressureBuffer() 15 | .Test().AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 16 | } 17 | 18 | [Test] 19 | public void OnBackpressureBuffer_Fused() 20 | { 21 | Flux.Range(1, 10).OnBackpressureBuffer() 22 | .Test(fusionMode: FuseableHelper.ANY) 23 | .AssertFusionMode(FuseableHelper.ASYNC) 24 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 25 | } 26 | [Test] 27 | public void OnBackpressureBuffer_Conditional() 28 | { 29 | Flux.Range(1, 10).OnBackpressureBuffer() 30 | .Filter(v => true) 31 | .Test().AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 32 | } 33 | 34 | [Test] 35 | public void OnBackpressureBuffer_Conditional_Fused() 36 | { 37 | Flux.Range(1, 10).OnBackpressureBuffer() 38 | .Filter(v => true) 39 | .Test(fusionMode: FuseableHelper.ANY) 40 | .AssertFusionMode(FuseableHelper.ASYNC) 41 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 42 | } 43 | 44 | [Test] 45 | public void OnBackpressureBuffer_Backpressured() 46 | { 47 | var ts = Flux.Range(1, 10).OnBackpressureBuffer() 48 | .Test(0); 49 | 50 | ts.AssertNoEvents(); 51 | 52 | ts.Request(2); 53 | 54 | ts.AssertValues(1, 2); 55 | 56 | ts.Request(5); 57 | 58 | ts.AssertValues(1, 2, 3, 4, 5, 6, 7); 59 | 60 | ts.Request(3); 61 | 62 | ts.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Reactor.Core.Test/OnBackpressureLatestTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class OnBackpressureLatestTest 9 | { 10 | [Test] 11 | public void OnBackpressureLatest_Normal() 12 | { 13 | var ps = new DirectProcessor(); 14 | 15 | var ts = ps.OnBackpressureLatest().Test(0); 16 | 17 | ps.OnNext(1); 18 | ps.OnNext(2); 19 | 20 | ts.Request(1); 21 | 22 | ps.OnNext(3); 23 | 24 | ts.Request(2); 25 | 26 | ps.OnNext(4); 27 | ps.OnComplete(); 28 | 29 | ts.AssertResult(2, 3, 4); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Reactor.Core.Test/OnErrorResumeWith.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class OnErrorResumeWithTest 9 | { 10 | [Test] 11 | public void OnErrorResumeWith_Normal() 12 | { 13 | Flux.Range(1, 5).OnErrorResumeWith(e => Flux.Range(6, 5)) 14 | .Test().AssertResult(1, 2, 3, 4, 5); 15 | } 16 | 17 | [Test] 18 | public void OnErrorResumeWith_Error() 19 | { 20 | Flux.Range(1, 5) 21 | .ConcatWith(Flux.Error(new Exception())) 22 | .OnErrorResumeWith(e => Flux.Range(6, 5)) 23 | .Test().AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 24 | } 25 | 26 | [Test] 27 | public void OnErrorResumeWith_Error_Backpressure() 28 | { 29 | var ts = Flux.Range(1, 5) 30 | .ConcatWith(Flux.Error(new Exception())) 31 | .OnErrorResumeWith(e => Flux.Range(6, 5)) 32 | .Test(4); 33 | 34 | ts.AssertValues(1, 2, 3, 4); 35 | 36 | ts.Request(4); 37 | 38 | ts.AssertValues(1, 2, 3, 4, 5, 6, 7, 8); 39 | 40 | ts.Request(2); 41 | 42 | ts.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ProcessTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class ProcessTest 9 | { 10 | [Test] 11 | public void Process_DirectProcessor() 12 | { 13 | 14 | var co = Flux.Range(1, 10).Process(() => new DirectProcessor(), o => o.Map(v => v + 1)); 15 | var ts = co.Test(); 16 | 17 | co.Connect(); 18 | 19 | ts.AssertResult(2, 3, 4, 5, 6, 7, 8, 9, 10, 11); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Reactor.Core.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Reactor.Core.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Reactor.Core.Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("325ee400-42df-4ef5-ba5c-6667cb9d3bbd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Reactor.Core.Test/PublishProcessorTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class PublishProcessorTest 9 | { 10 | [Test] 11 | public void PublishProcessor_Normal() 12 | { 13 | PublishProcessor pp = new PublishProcessor(); 14 | 15 | var ts1 = pp.Test(0); 16 | var ts2 = pp.Test(0); 17 | 18 | ts1.AssertNoEvents(); 19 | ts2.AssertNoValues(); 20 | 21 | Flux.Range(1, 10).Subscribe(pp); 22 | 23 | ts1.AssertNoEvents(); 24 | ts2.AssertNoValues(); 25 | 26 | ts1.Request(1); 27 | 28 | ts1.AssertNoEvents(); 29 | ts2.AssertNoValues(); 30 | 31 | ts2.Request(10); 32 | 33 | ts1.AssertValues(1); 34 | ts2.AssertValues(1); 35 | 36 | ts1.Request(9); 37 | 38 | ts1.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 39 | ts2.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Reactor.Core.Test/PublishSelectorTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class PublishSelectorTest 9 | { 10 | [Test] 11 | public void PublishSelector_Normal() 12 | { 13 | Flux.Range(1, 10).Publish(o => Flux.Zip(o, o.Skip(1), (a, b) => new Tuple(a, b))) 14 | .Test() 15 | .AssertResult( 16 | new Tuple(1, 2), 17 | new Tuple(2, 3), 18 | new Tuple(3, 4), 19 | new Tuple(4, 5), 20 | new Tuple(5, 6), 21 | new Tuple(6, 7), 22 | new Tuple(7, 8), 23 | new Tuple(8, 9), 24 | new Tuple(9, 10) 25 | ); 26 | } 27 | [Test] 28 | public void PublishSelector_Unrelated() 29 | { 30 | var dp = new DirectProcessor(); 31 | 32 | var ts = dp.Publish(o => Flux.Range(1, 10)).Test(0); 33 | 34 | Assert.IsTrue(dp.HasSubscribers, "No subscribers?"); 35 | 36 | ts.Request(10); 37 | 38 | ts.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 39 | 40 | Assert.IsFalse(dp.HasSubscribers, "Has subscribers?"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ReduceTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class ReduceTest 9 | { 10 | [Test] 11 | public void Reduce_Normal() 12 | { 13 | Flux.Range(1, 10).Reduce((a, b) => a + b).Test().AssertResult(55); 14 | } 15 | 16 | [Test] 17 | public void Reduce_InitialValue() 18 | { 19 | Flux.Range(1, 10).Reduce(10, (a, b) => a + b).Test().AssertResult(65); 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SampleTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SampleTest 9 | { 10 | [Test] 11 | public void Sample_Normal() 12 | { 13 | var dp1 = new DirectProcessor(); 14 | var dp2 = new DirectProcessor(); 15 | 16 | var ts = dp1.Sample(dp2).Test(); 17 | 18 | dp1.OnNext(1); 19 | dp1.OnNext(2); 20 | 21 | dp2.OnNext(1); 22 | dp2.OnNext(3); 23 | 24 | dp1.OnNext(3); 25 | 26 | dp2.OnComplete(); 27 | 28 | ts.AssertResult(2, 3); 29 | 30 | Assert.IsFalse(dp1.HasSubscribers, "dp1 has subscribers?!"); 31 | Assert.IsFalse(dp2.HasSubscribers, "dp2 has subscribers?!"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ScanTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class ScanTest 9 | { 10 | [Test] 11 | public void Scan_Normal() 12 | { 13 | Flux.Range(1, 10).Scan((a, b) => a + b).Test() 14 | .AssertResult(1, 3, 6, 10, 15, 21, 28, 36, 45, 55); 15 | } 16 | 17 | [Test] 18 | public void Scan_InitialValue() 19 | { 20 | Flux.Range(1, 10).Scan(10, (a, b) => a + b).Test() 21 | .AssertResult(10, 11, 13, 16, 20, 25, 31, 38, 46, 55, 65); 22 | } 23 | 24 | [Test] 25 | public void Scan_InitialValue_Backpressured() 26 | { 27 | var ts = Flux.Range(1, 10).Scan(10, (a, b) => a + b).Test(0); 28 | 29 | ts.AssertNoEvents(); 30 | 31 | ts.Request(2); 32 | 33 | ts.AssertValues(10, 11); 34 | 35 | ts.Request(8); 36 | 37 | ts.AssertValues(10, 11, 13, 16, 20, 25, 31, 38, 46, 55); 38 | 39 | ts.Request(1); 40 | 41 | ts.AssertResult(10, 11, 13, 16, 20, 25, 31, 38, 46, 55, 65); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SingleTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SingleTest 9 | { 10 | [Test] 11 | public void Single_Single() 12 | { 13 | Flux.Just(1).Single().Test().AssertResult(1); 14 | } 15 | 16 | [Test] 17 | public void Single_Empty_Default() 18 | { 19 | Flux.Empty().Single(2).Test().AssertResult(2); 20 | } 21 | 22 | [Test] 23 | public void Single_OrEmpty_Empty() 24 | { 25 | Flux.Empty().SingleOrEmpty().Test().AssertResult(); 26 | } 27 | 28 | [Test] 29 | public void Single_OrEmpty_Single() 30 | { 31 | Flux.Just(3).SingleOrEmpty().Test().AssertResult(3); 32 | } 33 | 34 | [Test] 35 | public void Single_Empty() 36 | { 37 | Flux.Empty().Single().Test() 38 | .AssertNoValues() 39 | .AssertError(e => e is IndexOutOfRangeException) 40 | .AssertNotComplete(); 41 | } 42 | 43 | [Test] 44 | public void Single_Many() 45 | { 46 | Flux.Range(1, 10).Single().Test() 47 | .AssertNoValues() 48 | .AssertError(e => e is IndexOutOfRangeException) 49 | .AssertNotComplete(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SkipLastTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SkipLastTest 9 | { 10 | [Test] 11 | public void SkipLast_Longer() 12 | { 13 | Flux.Range(1, 10).SkipLast(5) 14 | .Test().AssertResult(1, 2, 3, 4, 5); 15 | } 16 | 17 | [Test] 18 | public void SkipLast_Shorter() 19 | { 20 | Flux.Range(1, 10).SkipLast(15) 21 | .Test().AssertResult(); 22 | } 23 | 24 | [Test] 25 | public void SkipLast_Longer_Conditional() 26 | { 27 | Flux.Range(1, 10).SkipLast(5) 28 | .Filter(v => true) 29 | .Test().AssertResult(1, 2, 3, 4, 5); 30 | } 31 | 32 | [Test] 33 | public void SkipLast_Shorter_Conditional() 34 | { 35 | Flux.Range(1, 10).SkipLast(15) 36 | .Filter(v => true) 37 | .Test().AssertResult(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SkipTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SkipTest 9 | { 10 | [Test] 11 | public void Skip_Normal() 12 | { 13 | Flux.Range(1, 5).Skip(3).Test().AssertResult(4, 5); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SkipUntilTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SkipUntilTest 9 | { 10 | [Test] 11 | public void SkipUntil_Normal() 12 | { 13 | var dp1 = new DirectProcessor(); 14 | var dp2 = new DirectProcessor(); 15 | 16 | var ts = dp1.SkipUntil(dp2).Test(); 17 | 18 | dp1.OnNext(1, 2, 3); 19 | 20 | dp2.OnNext(1); 21 | 22 | dp1.OnNext(4, 5, 6); 23 | dp1.OnComplete(); 24 | 25 | Assert.IsFalse(dp2.HasSubscribers, "Has subscribers?!"); 26 | 27 | ts.AssertResult(4, 5, 6); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SkipWhileTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class SkipWhileTest 10 | { 11 | [Test] 12 | public void SkipWhile_Normal() 13 | { 14 | Flux.Range(1, 10).SkipWhile(v => v < 6) 15 | .Test().AssertResult(6, 7, 8, 9, 10); 16 | } 17 | 18 | [Test] 19 | public void SkipWhile_Conditional() 20 | { 21 | Flux.Range(1, 10).SkipWhile(v => v < 6) 22 | .Filter(v => true) 23 | .Test().AssertResult(6, 7, 8, 9, 10); 24 | } 25 | 26 | [Test] 27 | public void SkipWhile_Normal_Fused() 28 | { 29 | Flux.Range(1, 10).SkipWhile(v => v < 6) 30 | .Test(fusionMode: FuseableHelper.ANY) 31 | .AssertFusionMode(FuseableHelper.SYNC) 32 | .AssertResult(6, 7, 8, 9, 10); 33 | } 34 | 35 | [Test] 36 | public void SkipWhile_Conditional_Fused() 37 | { 38 | Flux.Range(1, 10).SkipWhile(v => v < 6) 39 | .Filter(v => true) 40 | .Test(fusionMode: FuseableHelper.ANY) 41 | .AssertFusionMode(FuseableHelper.SYNC) 42 | .AssertResult(6, 7, 8, 9, 10); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SubscribeOnTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using Reactor.Core.scheduler; 4 | using System; 5 | 6 | namespace Reactor.Core.Test 7 | { 8 | [TestFixture] 9 | [Timeout(30000)] 10 | public class SubscribeOnTest 11 | { 12 | [Test] 13 | public void SubscribeOn_Normal() 14 | { 15 | Flux.Range(1, 10).SubscribeOn(DefaultScheduler.Instance) 16 | .Test().AwaitTerminalEvent() 17 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 18 | } 19 | 20 | [Test] 21 | public void SubscribeOn_Scalar() 22 | { 23 | Flux.Just(1).SubscribeOn(DefaultScheduler.Instance) 24 | .Test().AwaitTerminalEvent() 25 | .AssertResult(1); 26 | } 27 | 28 | [Test] 29 | public void SubscribeOn_Callable() 30 | { 31 | Flux.From(() => 1).SubscribeOn(DefaultScheduler.Instance) 32 | .Test().AwaitTerminalEvent() 33 | .AssertResult(1); 34 | } 35 | 36 | [Test] 37 | public void SubscribeOn_ScalarFused() 38 | { 39 | Flux.Just(1).SubscribeOn(DefaultScheduler.Instance) 40 | .Test(fusionMode: FuseableHelper.ANY) 41 | .AwaitTerminalEvent() 42 | .AssertFusionMode(FuseableHelper.ASYNC) 43 | .AssertResult(1); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SwitchIfEmptyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SwitchIfEmptyTest 9 | { 10 | [Test] 11 | public void SwitchIfEmpty_Empty() 12 | { 13 | Flux.Empty().SwitchIfEmpty(Flux.Range(1, 10)) 14 | .Test() 15 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 16 | } 17 | 18 | [Test] 19 | public void SwitchIfEmpty_NonEmpty() 20 | { 21 | Flux.Range(11, 10).SwitchIfEmpty(Flux.Range(1, 10)) 22 | .Test() 23 | .AssertResult(11, 12, 13, 14, 15, 16, 17, 18, 19, 20); 24 | } 25 | 26 | [Test] 27 | public void SwitchIfEmpty_Conditional_Empty() 28 | { 29 | Flux.Empty().SwitchIfEmpty(Flux.Range(1, 10)) 30 | .Filter(v => true) 31 | .Test() 32 | .AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 33 | } 34 | 35 | [Test] 36 | public void SwitchIfEmpty_Conditional_NonEmpty() 37 | { 38 | Flux.Range(11, 10).SwitchIfEmpty(Flux.Range(1, 10)) 39 | .Filter(v => true) 40 | .Test() 41 | .AssertResult(11, 12, 13, 14, 15, 16, 17, 18, 19, 20); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Reactor.Core.Test/SwitchMapTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class SwitchMapTest 9 | { 10 | [Test] 11 | public void SwitchMap_Normal() 12 | { 13 | var dp = new DirectProcessor(); 14 | 15 | var ts = dp.SwitchMap(v => Flux.Range(v, 2).Hide()) 16 | .Test(); 17 | 18 | dp.OnNext(1, 2, 3); 19 | dp.OnComplete(); 20 | 21 | ts.AssertResult(1, 2, 2, 3, 3, 4); 22 | } 23 | 24 | [Test] 25 | public void SwitchMap_Normal_Fused() 26 | { 27 | var dp = new DirectProcessor(); 28 | 29 | var ts = dp.SwitchMap(v => Flux.Range(v, 2)) 30 | .Test(); 31 | 32 | dp.OnNext(1, 2, 3); 33 | dp.OnComplete(); 34 | 35 | ts.AssertResult(1, 2, 2, 3, 3, 4); 36 | } 37 | 38 | [Test] 39 | public void SwitchMap_Normal_Backpressured() 40 | { 41 | var dp = new DirectProcessor(); 42 | 43 | var ts = dp.SwitchMap(v => Flux.Range(v, 2)) 44 | .Test(initialRequest: 1); 45 | 46 | dp.OnNext(1); 47 | 48 | dp.OnNext(2); 49 | 50 | ts.Request(1); 51 | 52 | dp.OnNext(3); 53 | 54 | ts.Request(1); 55 | 56 | dp.OnComplete(); 57 | 58 | ts.Request(1); 59 | 60 | ts.AssertResult(1, 2, 3, 4); 61 | 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Reactor.Core.Test/TakeLastTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class TakeLastTest 10 | { 11 | [Test] 12 | public void TakeLast_Longer() 13 | { 14 | Flux.Range(1, 10).TakeLast(15) 15 | .Test().AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 16 | } 17 | 18 | 19 | [Test] 20 | public void TakeLast_Longer_Backpressured() 21 | { 22 | var ts = Flux.Range(1, 10).TakeLast(15) 23 | .Test(0); 24 | 25 | ts.AssertNoEvents(); 26 | 27 | ts.Request(2); 28 | 29 | ts.AssertValues(1, 2); 30 | 31 | ts.Request(5); 32 | 33 | ts.AssertValues(1, 2, 3, 4, 5, 6, 7); 34 | 35 | ts.Request(3); 36 | 37 | ts.AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 38 | } 39 | 40 | [Test] 41 | public void TakeLast_Shorter() 42 | { 43 | Flux.Range(1, 10).TakeLast(5) 44 | .Test().AssertResult(6, 7, 8, 9, 10); 45 | } 46 | 47 | [Test] 48 | public void TakeLast_Longer_Conditional() 49 | { 50 | Flux.Range(1, 10).TakeLast(15) 51 | .Filter(v => true) 52 | .Test().AssertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 53 | } 54 | 55 | [Test] 56 | public void TakeLast_Shorter_Conditional() 57 | { 58 | Flux.Range(1, 10).TakeLast(5) 59 | .Filter(v => true) 60 | .Test().AssertResult(6, 7, 8, 9, 10); 61 | } 62 | 63 | [Test] 64 | public void TakeLast_Single() 65 | { 66 | Flux.Range(1, 10).TakeLast(1) 67 | .Test().AssertResult(10); 68 | } 69 | 70 | [Test] 71 | public void TakeLast_Single_Fused() 72 | { 73 | Flux.Range(1, 10).TakeLast(1) 74 | .Test(fusionMode: FuseableHelper.ANY) 75 | .AssertFusionMode(FuseableHelper.ASYNC) 76 | .AssertResult(10); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Reactor.Core.Test/TakeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Reactor.Core.flow; 3 | using Reactor.Core.scheduler; 4 | using NUnit.Framework; 5 | 6 | namespace Reactor.Core.Test 7 | { 8 | [TestFixture] 9 | [Timeout(30000)] 10 | public class TakeTest 11 | { 12 | [Test] 13 | public void Take_Fused_Exact_Boundary_Backpressure() 14 | { 15 | 16 | var ts = Flux.Range(1, 2) 17 | .Take(1) 18 | .PublishOn(ImmediateScheduler.Instance) 19 | .Test(1, FuseableHelper.ANY); 20 | 21 | ts.AssertResult(1); 22 | } 23 | 24 | [Test] 25 | public void Take_Normal() 26 | { 27 | Flux.Range(1, 10).Take(5).Test().AssertResult(1, 2, 3, 4, 5); 28 | } 29 | 30 | [Test] 31 | public void Take_Normal_Backpressured() 32 | { 33 | var ts = Flux.Range(1, 10).Take(5).Test(0L); 34 | 35 | ts.AssertNoEvents(); 36 | 37 | ts.Request(1); 38 | 39 | ts.AssertValues(1); 40 | 41 | ts.Request(2); 42 | 43 | ts.AssertValues(1, 2, 3); 44 | 45 | ts.Request(2); 46 | 47 | ts.AssertResult(1, 2, 3, 4, 5); 48 | } 49 | 50 | [Test] 51 | public void Take_Exact_Number_Sync_Fused() 52 | { 53 | Flux.Range(1, 5).Take(5).Test(fusionMode: FuseableHelper.SYNC) 54 | .AssertResult(1, 2, 3, 4, 5); 55 | } 56 | 57 | [Test] 58 | public void Take_Exact_Number_Async_Fused() 59 | { 60 | var up = new UnicastProcessor(); 61 | up.OnNext(1, 2, 3, 4, 5); 62 | 63 | up.Take(5).Test(fusionMode: FuseableHelper.ASYNC) 64 | .AssertResult(1, 2, 3, 4, 5); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Reactor.Core.Test/TakeUntilPredicateTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class TakeUntilPredicateTest 10 | { 11 | [Test] 12 | public void TakeUntilPredicate_Normal() 13 | { 14 | Flux.Range(1, 10).TakeUntil(v => v == 5) 15 | .Test().AssertResult(1, 2, 3, 4, 5); 16 | } 17 | 18 | [Test] 19 | public void TakeUntilPredicate_Conditional() 20 | { 21 | Flux.Range(1, 10).TakeUntil(v => v == 5) 22 | .Filter(v => true) 23 | .Test().AssertResult(1, 2, 3, 4, 5); 24 | } 25 | 26 | [Test] 27 | public void TakeUntilPredicate_Normal_Fused() 28 | { 29 | Flux.Range(1, 10).TakeUntil(v => v == 5) 30 | .Test(fusionMode: FuseableHelper.ANY) 31 | .AssertFusionMode(FuseableHelper.SYNC) 32 | .AssertResult(1, 2, 3, 4, 5); 33 | } 34 | 35 | [Test] 36 | public void TakeUntilPredicate_Conditional_Fused() 37 | { 38 | Flux.Range(1, 10).TakeUntil(v => v == 5) 39 | .Filter(v => true) 40 | .Test(fusionMode: FuseableHelper.ANY) 41 | .AssertFusionMode(FuseableHelper.SYNC) 42 | .AssertResult(1, 2, 3, 4, 5); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Reactor.Core.Test/TakeUntilTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class TakeUntilTest 9 | { 10 | [Test] 11 | public void TakeUntil_Normal() 12 | { 13 | var dp1 = new DirectProcessor(); 14 | var dp2 = new DirectProcessor(); 15 | 16 | var ts = dp1.TakeUntil(dp2).Test(); 17 | 18 | dp1.OnNext(1, 2, 3); 19 | 20 | dp2.OnNext(1); 21 | 22 | ts.AssertResult(1, 2, 3); 23 | 24 | Assert.IsFalse(dp1.HasSubscribers, "dp1 has Subscribers?!"); 25 | Assert.IsFalse(dp2.HasSubscribers, "dp2 has Subscribers?!"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Reactor.Core.Test/TakeWhileTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class TakeWhileTest 10 | { 11 | [Test] 12 | public void TakeWhile_Normal() 13 | { 14 | Flux.Range(1, 10).TakeWhile(v => v <= 5) 15 | .Test().AssertResult(1, 2, 3, 4, 5); 16 | } 17 | 18 | [Test] 19 | public void TakeWhile_Conditional() 20 | { 21 | Flux.Range(1, 10).TakeWhile(v => v <= 5) 22 | .Filter(v => true) 23 | .Test().AssertResult(1, 2, 3, 4, 5); 24 | } 25 | 26 | [Test] 27 | public void TakeWhile_Normal_Fused() 28 | { 29 | Flux.Range(1, 10).TakeWhile(v => v <= 5) 30 | .Test(fusionMode: FuseableHelper.ANY) 31 | .AssertFusionMode(FuseableHelper.SYNC) 32 | .AssertResult(1, 2, 3, 4, 5); 33 | } 34 | 35 | [Test] 36 | public void TakeWhile_Conditional_Fused() 37 | { 38 | Flux.Range(1, 10).TakeWhile(v => v <= 5) 39 | .Filter(v => true) 40 | .Test(fusionMode: FuseableHelper.ANY) 41 | .AssertFusionMode(FuseableHelper.SYNC) 42 | .AssertResult(1, 2, 3, 4, 5); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ThenManyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class ThenManyTest 10 | { 11 | [Test] 12 | public void ThenMany_Normal() 13 | { 14 | Flux.Range(1, 10) 15 | .ThenMany(Flux.Range(11, 10)) 16 | .Test() 17 | .AssertResult(11, 12, 13, 14, 15, 16, 17, 18, 19, 20); 18 | } 19 | 20 | [Test] 21 | public void ThenMany_Conditional() 22 | { 23 | Flux.Range(1, 10) 24 | .ThenMany(Flux.Range(11, 10)) 25 | .Filter(v => true) 26 | .Test() 27 | .AssertResult(11, 12, 13, 14, 15, 16, 17, 18, 19, 20); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ThenTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class ThenTest 10 | { 11 | [Test] 12 | public void Then_EmptyVoid() 13 | { 14 | Flux.Range(1, 10).Then(Mono.Empty()) 15 | .Test().AssertResult(); 16 | } 17 | 18 | [Test] 19 | public void Then_EmptyVoid_Fused() 20 | { 21 | Flux.Range(1, 10).Then(Mono.Empty()) 22 | .Test(fusionMode: FuseableHelper.ANY) 23 | .AssertFusionMode(FuseableHelper.ASYNC) 24 | .AssertResult(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ToEnumerableTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace Reactor.Core.Test 7 | { 8 | [TestFixture] 9 | [Timeout(30000)] 10 | public class ToEnumerableTest 11 | { 12 | [Test] 13 | public void ToEnumerable_Normal() 14 | { 15 | var ie = Flux.Range(1, 5).Hide().ToEnumerable(); 16 | 17 | List expected = new List(); 18 | for (int i = 1; i <= 5; i++) 19 | { 20 | expected.Add(i); 21 | } 22 | 23 | List list = new List(); 24 | 25 | foreach (var i in ie) 26 | { 27 | list.Add(i); 28 | } 29 | 30 | Assert.AreEqual(5, list.Count); 31 | Assert.AreEqual(expected, list); 32 | } 33 | 34 | [Test] 35 | public void ToEnumerable_Normal_Sync_Fused() 36 | { 37 | var ie = Flux.Range(1, 5).ToEnumerable(); 38 | 39 | List expected = new List(); 40 | for (int i = 1; i <= 5; i++) 41 | { 42 | expected.Add(i); 43 | } 44 | 45 | List list = new List(); 46 | 47 | foreach (var i in ie) 48 | { 49 | list.Add(i); 50 | } 51 | 52 | Assert.AreEqual(5, list.Count); 53 | Assert.AreEqual(expected, list); 54 | } 55 | 56 | [Test, Timeout(5000)] 57 | public void ToEnumerable_Normal_Async_Fused_Online() 58 | { 59 | var up = new UnicastProcessor(); 60 | 61 | var ie = up.ToEnumerable(); 62 | 63 | Task.Run(() => 64 | { 65 | up.OnNext(1, 2, 3, 4, 5); 66 | up.OnComplete(); 67 | }); 68 | 69 | 70 | 71 | List expected = new List(); 72 | for (int i = 1; i <= 5; i++) 73 | { 74 | expected.Add(i); 75 | } 76 | 77 | List list = new List(); 78 | 79 | foreach (var i in ie) 80 | { 81 | list.Add(i); 82 | } 83 | 84 | Assert.AreEqual(5, list.Count); 85 | Assert.AreEqual(expected, list); 86 | } 87 | 88 | [Test, Timeout(50000)] 89 | public void ToEnumerable_Normal_Sync_Fused_Offline() 90 | { 91 | var up = new UnicastProcessor(); 92 | 93 | List expected = new List(); 94 | for (int i = 1; i <= 5; i++) 95 | { 96 | expected.Add(i); 97 | up.OnNext(i); 98 | } 99 | up.OnComplete(); 100 | 101 | var ie = up.ToEnumerable(); 102 | 103 | List list = new List(); 104 | 105 | foreach (var i in ie) 106 | { 107 | list.Add(i); 108 | } 109 | 110 | Assert.AreEqual(5, list.Count); 111 | Assert.AreEqual(expected, list); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Reactor.Core.Test/UsingTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Reactor.Core.flow; 3 | using System; 4 | 5 | namespace Reactor.Core.Test 6 | { 7 | [TestFixture] 8 | [Timeout(30000)] 9 | public class UsingTest 10 | { 11 | [Test] 12 | public void Using_Normal() 13 | { 14 | Flux.Using(() => 1, s => Flux.Range(1, 5), s => { }) 15 | .Test().AssertResult(1, 2, 3, 4, 5); 16 | } 17 | 18 | [Test] 19 | public void Using_Normal_Fused() 20 | { 21 | Flux.Using(() => 1, s => Flux.Range(1, 5), s => { }) 22 | .Test(fusionMode: FuseableHelper.ANY) 23 | .AssertFusionMode(FuseableHelper.SYNC) 24 | .AssertResult(1, 2, 3, 4, 5); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Reactor.Core.Test/WithLatestFromTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class WithLatestFromTest 9 | { 10 | [Test] 11 | public void WithLatestFrom_Normal() 12 | { 13 | var dp1 = new DirectProcessor(); 14 | var dp2 = new DirectProcessor(); 15 | 16 | var ts = dp1.WithLatestFrom(dp2, (a, b) => a + b).Test(); 17 | 18 | dp1.OnNext(1); 19 | 20 | dp2.OnNext(10); 21 | 22 | dp1.OnNext(2, 3, 4); 23 | 24 | dp2.OnNext(20); 25 | 26 | dp1.OnNext(5); 27 | dp1.OnComplete(); 28 | 29 | ts.AssertResult(12, 13, 14, 25); 30 | 31 | Assert.IsFalse(dp1.HasSubscribers, "dp1 has subscribers?"); 32 | Assert.IsFalse(dp2.HasSubscribers, "dp2 has subscribers?"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ZipEnumerableTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Reactor.Core.flow; 3 | using Reactor.Core.scheduler; 4 | using NUnit.Framework; 5 | using System.Collections.Generic; 6 | 7 | namespace Reactor.Core.Test 8 | { 9 | [TestFixture] 10 | [Timeout(30000)] 11 | public class ZipEnumerableTest 12 | { 13 | 14 | static IEnumerable Range(int start, int count) 15 | { 16 | for (int i = start; i != start + count; i++) 17 | { 18 | yield return i; 19 | } 20 | //yield break; 21 | } 22 | 23 | [Test] 24 | public void ZipEnumerable_Normal() 25 | { 26 | Flux.Range(1, 5).ZipWith(Range(1, 5), (a, b) => a * 10 + b) 27 | .Test().AssertResult(11, 22, 33, 44, 55); 28 | } 29 | 30 | [Test] 31 | public void ZipEnumerable_Main_Sorter() 32 | { 33 | Flux.Range(1, 5).ZipWith(Range(1, 6), (a, b) => a * 10 + b) 34 | .Test().AssertResult(11, 22, 33, 44, 55); 35 | } 36 | 37 | [Test] 38 | public void ZipEnumerable_Other_Sorter() 39 | { 40 | Flux.Range(1, 5).ZipWith(Range(1, 4), (a, b) => a * 10 + b) 41 | .Test().AssertResult(11, 22, 33, 44); 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Reactor.Core.Test/ZipTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Reactor.Core.Test 5 | { 6 | [TestFixture] 7 | [Timeout(30000)] 8 | public class ZipTest 9 | { 10 | [Test] 11 | public void Zip_Normal() 12 | { 13 | Flux.Zip(Flux.Range(1, 2).Hide(), Flux.Range(1, 2).Hide(), (a, b) => a * 10 + b) 14 | .Test().AssertResult(11, 22); 15 | } 16 | 17 | [Test] 18 | public void Zip_First_Shorter() 19 | { 20 | Flux.Zip(Flux.Range(1, 2).Hide(), Flux.Range(1, 3).Hide(), (a, b) => a * 10 + b) 21 | .Test().AssertResult(11, 22); 22 | } 23 | 24 | [Test] 25 | public void Zip_Second_Shorter() 26 | { 27 | Flux.Zip(Flux.Range(1, 3).Hide(), Flux.Range(1, 2).Hide(), (a, b) => a * 10 + b) 28 | .Test().AssertResult(11, 22); 29 | } 30 | 31 | [Test] 32 | public void Zip_First_Empty() 33 | { 34 | Flux.Zip(Flux.Empty().Hide(), Flux.Range(1, 3).Hide(), (a, b) => a * 10 + b) 35 | .Test().AssertResult(); 36 | } 37 | 38 | [Test] 39 | public void Zip_Second_Empty() 40 | { 41 | Flux.Zip(Flux.Range(1, 2).Hide(), Flux.Empty().Hide(), (a, b) => a * 10 + b) 42 | .Test().AssertResult(); 43 | } 44 | 45 | [Test] 46 | public void Zip_Normal_Fused() 47 | { 48 | Flux.Zip(Flux.Range(1, 2), Flux.Range(1, 2), (a, b) => a * 10 + b) 49 | .Test().AssertResult(11, 22); 50 | } 51 | 52 | [Test] 53 | public void Zip_First_Shorter_Fused() 54 | { 55 | Flux.Zip(Flux.Range(1, 2), Flux.Range(1, 3), (a, b) => a * 10 + b) 56 | .Test().AssertResult(11, 22); 57 | } 58 | 59 | [Test] 60 | public void Zip_Second_Shorter_Fused() 61 | { 62 | Flux.Zip(Flux.Range(1, 3), Flux.Range(1, 2), (a, b) => a * 10 + b) 63 | .Test().AssertResult(11, 22); 64 | } 65 | 66 | [Test] 67 | public void Zip_First_Empty_Fused() 68 | { 69 | Flux.Zip(Flux.Empty(), Flux.Range(1, 3), (a, b) => a * 10 + b) 70 | .Test().AssertResult(); 71 | } 72 | 73 | [Test] 74 | public void Zip_Second_Empty_Fused() 75 | { 76 | Flux.Zip(Flux.Range(1, 2), Flux.Empty(), (a, b) => a * 10 + b) 77 | .Test().AssertResult(); 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Reactor.Core.Test/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Reactor.Core.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Reactor.Core.Test/tck/ConcatTckTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.Test.tck 16 | { 17 | class ConcatTest : FluxPublisherVerification 18 | { 19 | public override IPublisher CreatePublisher(long elements) 20 | => Flux.From(Enumerate(elements/2)).ConcatWith(Flux.From(Enumerate((elements + 1)/2))).Tck(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Reactor.Core.Test/tck/FluxPublisherVerification.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | using Reactive.Streams; 6 | using Reactive.Streams.TCK; 7 | using Reactive.Streams.TCK.Support; 8 | 9 | namespace Reactor.Core.Test.tck 10 | { 11 | [TestFixture] 12 | abstract class FluxPublisherVerification : PublisherVerification 13 | { 14 | protected FluxPublisherVerification() : base(new TestEnvironment()) 15 | { 16 | } 17 | 18 | public override IPublisher CreateFailedPublisher() => Flux.Error(new TestException()); 19 | 20 | protected IEnumerable Enumerate(long elements) => Enumerate(elements > int.MaxValue, elements); 21 | 22 | protected IEnumerable Enumerate(bool useInfinite, long elements) 23 | => useInfinite 24 | ? new InfiniteEnumerable() 25 | : Enumerable.Range(0, (int)elements); 26 | 27 | 28 | private sealed class InfiniteEnumerable : IEnumerable 29 | { 30 | public IEnumerator GetEnumerator() => new InfiniteEnumerator(); 31 | 32 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 33 | 34 | private sealed class InfiniteEnumerator : IEnumerator 35 | { 36 | private int _current; 37 | 38 | public void Dispose() 39 | { 40 | 41 | } 42 | 43 | public bool MoveNext() 44 | { 45 | _current++; 46 | return true; 47 | } 48 | 49 | public void Reset() => _current = 0; 50 | 51 | public int Current => _current; 52 | 53 | object IEnumerator.Current => Current; 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Reactor.Core/BackpressureHandling.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core 15 | { 16 | /// 17 | /// Handling of backpressure for FluxEmitter and IObservable conversions. 18 | /// 19 | public enum BackpressureHandling 20 | { 21 | /// 22 | /// Completely ignore backpressure. 23 | /// 24 | None, 25 | /// 26 | /// Signal an error if the downstream can't keep up. 27 | /// 28 | Error, 29 | /// 30 | /// Drop the overflown item. 31 | /// 32 | Drop, 33 | /// 34 | /// Keep only the latest item. 35 | /// 36 | Latest, 37 | /// 38 | /// Buffer all items. 39 | /// 40 | Buffer 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Reactor.Core/ConcatErrorMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core 15 | { 16 | /// 17 | /// Indicates when an error should be delivered in a Concat/ConcatMap operator. 18 | /// 19 | public enum ConcatErrorMode 20 | { 21 | /// 22 | /// If any of the participating IPublisher signals an OnError, that error is delivered immediately. 23 | /// 24 | Immediate, 25 | /// 26 | /// If any of the participating IPublisher signals an OnError, that error is delivered when the current 27 | /// inner IPublisher terminates. If multiple OnError signals happened, 28 | /// the downstream will receive all of them in an AggregateException. 29 | /// 30 | Boundary, 31 | /// 32 | /// If any of the participating IPublisher signals an OnError, that error is delivered only when 33 | /// the outer and all the inner IPublishers have terminated. If multiple OnError signals happened, 34 | /// the downstream will receive all of them in an AggregateException. 35 | /// 36 | End 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Reactor.Core/ConnectableFlux.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core 16 | { 17 | /// 18 | /// Extension methods to work with instances. 19 | /// 20 | public static class ConnectableFlux 21 | { 22 | /// 23 | /// Automatically connect to the source if the number of arriving 24 | /// ISubscribers reaches the specified number. 25 | /// 26 | /// The value type. 27 | /// The source IConnectableFlux to connect to. 28 | /// The minimum number of Subscribers to connect to the source. 29 | /// Zero connects immediately. 30 | /// The callback to receive a disposable that let's disconnect 31 | /// the established connection. 32 | /// The new IFlux instance. 33 | public static IFlux AutoConnect(this IConnectableFlux source, int n = 1, Action onConnect = null) 34 | { 35 | // TODO 36 | throw new NotImplementedException(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Reactor.Core/IConnectableFlux.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// Represents a connectable IFlux that starts streaming 16 | /// only when the is called. 17 | /// 18 | /// The value type 19 | public interface IConnectableFlux : IFlux 20 | { 21 | /// 22 | /// Connect to the upstream IFlux. 23 | /// 24 | /// If given, it is called with a disposable instance that allows in-sequence connectioncancellation. 25 | /// The IDisposable to cancel the connection 26 | IDisposable Connect(Action onConnect = null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Reactor.Core/IFlux.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// A Reactive Streams with rx operators that emits 0 to N elements, and then completes 16 | /// (successfully or with an error). 17 | /// 18 | /// 19 | ///

20 | /// 21 | ///

22 | /// 23 | ///

It is intended to be used in implementations and return types.Input parameters should keep using raw 24 | /// Publisher as much as possible.

25 | /// 26 | ///

If it is known that the underlying Publisher 27 | /// will emit 0 or 1 element, Mono should be used 28 | /// instead.

29 | ///
30 | 31 | public interface IFlux : IPublisher 32 | { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Reactor.Core/IFluxEmitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// API surface to signal 0 to N elements followed by an optional error or completion, 16 | /// hiding an actual ISubscriber. 17 | /// 18 | public interface IFluxEmitter 19 | { 20 | /// 21 | /// Signal the next value. 22 | /// 23 | /// The value. 24 | void Next(T t); 25 | 26 | /// 27 | /// Signal an error. Disposes any associated resource. 28 | /// 29 | /// 30 | void Error(Exception e); 31 | 32 | /// 33 | /// Signal a completion. Disposes any associated resource. 34 | /// 35 | void Complete(); 36 | 37 | /// 38 | /// Associate a resource with the emitter that should 39 | /// be disposed on completion or cancellation 40 | /// 41 | /// The resource to associate. 42 | void SetDisposable(IDisposable d); 43 | 44 | /// 45 | /// The current requested amount. 46 | /// 47 | long Requested { get; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Reactor.Core/IFluxProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// An IFlux-typed . 16 | /// 17 | /// The input and output value type. 18 | public interface IFluxProcessor : IFluxProcessor, IProcessor 19 | { 20 | } 21 | 22 | /// 23 | /// An IFlux-typed . 24 | /// 25 | /// The input value type. 26 | /// The output value type 27 | public interface IFluxProcessor : IFlux, IProcessor 28 | { 29 | /// 30 | /// Returns true if this IProcessor has subscribers. 31 | /// 32 | bool HasSubscribers { get; } 33 | 34 | /// 35 | /// Returns true if this IProcessor has completed normally. 36 | /// 37 | bool IsComplete { get; } 38 | 39 | /// 40 | /// Returns true if this IProcessor has failed. 41 | /// 42 | bool HasError { get; } 43 | 44 | /// 45 | /// Returns the failure Exception if 46 | /// returns true, null otherwise. 47 | /// 48 | Exception Error { get; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Reactor.Core/IGroupedFlux.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// Represents an IFlux with a key. 16 | /// 17 | /// The key type 18 | /// The value type 19 | public interface IGroupedFlux : IFlux 20 | { 21 | /// 22 | /// The key associated with this group. 23 | /// 24 | K Key { get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Reactor.Core/IMono.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// A Reactive Streams Publisher 16 | /// with basic rx operators that completes successfully by emitting an element, or 17 | /// with an error. 18 | /// 19 | public interface IMono : IPublisher 20 | { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Reactor.Core/IMonoEmitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// API surface to signal completion, 1 element followed by a completion or 1 error only, 16 | /// hiding an actual ISubscriber. 17 | /// 18 | public interface IMonoEmitter 19 | { 20 | /// 21 | /// Signal the single value and complete. Disposes any associated resource. 22 | /// 23 | /// The value. 24 | void Complete(T t); 25 | 26 | /// 27 | /// Signal an error. Disposes any associated resource. 28 | /// 29 | /// 30 | void Error(Exception e); 31 | 32 | /// 33 | /// Signal a completion. Disposes any associated resource. 34 | /// 35 | void Complete(); 36 | 37 | /// 38 | /// Indicate no more signals will follow. Further calls 39 | /// to the other methods are ignored. 40 | /// 41 | void Stop(); 42 | 43 | /// 44 | /// Associate a resource with the emitter that should 45 | /// be disposed on completion or cancellation 46 | /// 47 | /// The resource to associate. 48 | void SetDisposable(IDisposable d); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Reactor.Core/IOrderedItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Reactor.Core 8 | { 9 | /// 10 | /// Base interface for indexed one element container. 11 | /// 12 | /// The contained value type 13 | public interface IOrderedItem : IComparable> 14 | { 15 | /// 16 | /// The index of the contained element. 17 | /// 18 | long Index { get; } 19 | 20 | /// 21 | /// The contained element. 22 | /// 23 | T Value { get; } 24 | 25 | /// 26 | /// Returns an IOrderedItem with the same index but different value content. 27 | /// 28 | /// The result value type. 29 | /// The replacement value. 30 | /// The IOrderedItem with the same index as this and the given value as content. 31 | IOrderedItem Replace(R value); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Reactor.Core/ISignalEmitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core 13 | { 14 | /// 15 | /// API for emitting signals based on requests. 16 | /// 17 | /// The value type. 18 | public interface ISignalEmitter 19 | { 20 | /// 21 | /// Signal the next value. Should be called at most once per generator invocation. 22 | /// 23 | /// The value to signal 24 | void Next(T t); 25 | 26 | /// 27 | /// Signal an error. Can be called directly after calling . 28 | /// 29 | /// 30 | void Error(Exception e); 31 | 32 | /// 33 | /// Signal a completion. Can be called directly after calling . 34 | /// 35 | void Complete(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Reactor.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("reactor-core-dotnet")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("reactor-core-dotnet")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Reactor.Core/Timed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core 16 | { 17 | /// 18 | /// Structure holding a value and an Utc timestamp or time interval. 19 | /// 20 | /// The value type 21 | public struct Timed 22 | { 23 | /// 24 | /// The held value. 25 | /// 26 | public T Value { get; private set; } 27 | 28 | /// 29 | /// The held timestamp 30 | /// 31 | public long TimeMillis { get; private set; } 32 | 33 | /// 34 | /// Initializes the Timed instance. 35 | /// 36 | /// The value 37 | /// The time in milliseconds 38 | public Timed(T value, long timeMillis) 39 | { 40 | Value = value; 41 | TimeMillis = timeMillis; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Reactor.Core/Void.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core 16 | { 17 | /// 18 | /// A type that can't have instances. 19 | /// 20 | public sealed class Void 21 | { 22 | private Void() 23 | { 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Reactor.Core/flow/FuseableHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Reactor.Core.flow 8 | { 9 | /// 10 | /// Constants for parameter 11 | /// and return types. 12 | /// 13 | public static class FuseableHelper 14 | { 15 | /// 16 | /// Returned by the method to indicate no fusion will take place. 17 | /// 18 | public static readonly int NONE = 0; 19 | 20 | /// 21 | /// Requested and returned by the to indicate synchronous fusion. 22 | /// 23 | public static readonly int SYNC = 1; 24 | 25 | /// 26 | /// Requested and returned by the method to indicate asynchronous fusion. 27 | /// 28 | public static readonly int ASYNC = 2; 29 | 30 | /// 31 | /// Combination of and constants. 32 | /// 33 | public static readonly int ANY = SYNC | ASYNC; 34 | 35 | /// 36 | /// Requested and returned by the method 37 | /// to indicate that the requestor is a thread-boundary. 38 | /// 39 | public static readonly int BOUNDARY = 4; 40 | 41 | /// 42 | /// Handle the case when the is called on a 43 | /// . 44 | /// 45 | /// Never completes normally. 46 | public static bool DontCallOffer() 47 | { 48 | throw new InvalidOperationException("IQueueSubscription.Offer mustn't be called."); 49 | } 50 | 51 | /// 52 | /// Convert the mode flags into a string. 53 | /// 54 | /// The mode flags. 55 | /// The string representing the mode flags. 56 | public static string ToString(int mode) 57 | { 58 | string result = ""; 59 | if (mode == 0) 60 | { 61 | return "NONE"; 62 | } 63 | if ((mode & SYNC) != 0) 64 | { 65 | result += "SYNC | "; 66 | } 67 | if ((mode & ASYNC) != 0) 68 | { 69 | result += "ASYNC | "; 70 | } 71 | if ((mode & BOUNDARY) != 0) 72 | { 73 | result += "ASYNC | "; 74 | } 75 | return result.Substring(0, result.Length - 3); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Reactor.Core/flow/ICallable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core.flow 13 | { 14 | /// 15 | /// Indicates an IPublisher holds a single value that can be computed or 16 | /// retrieved at subscription time. 17 | /// 18 | /// The returned value type. 19 | public interface ICallable 20 | { 21 | /// 22 | /// Returns the value. 23 | /// 24 | T Value { get; } 25 | } 26 | 27 | /// 28 | /// Indicates an IPublisher holds a single, constant value that can 29 | /// be retrieved at assembly time. 30 | /// 31 | /// The returned value type. 32 | public interface IScalarCallable : ICallable 33 | { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Reactor.Core/flow/IConditionalSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core.flow 13 | { 14 | /// 15 | /// Represents a conditional ISubscriber that has a TryOnNext() method 16 | /// to avoid requesting replenishments one-by-one 17 | /// 18 | /// The value type 19 | public interface IConditionalSubscriber : ISubscriber 20 | { 21 | /// 22 | /// Try signalling a value and return true if successful, 23 | /// false to indicate a new value can be immediately sent out. 24 | /// 25 | /// The value signalled 26 | /// True if the value has been consumed, false if a new value can be 27 | /// sent immediately 28 | bool TryOnNext(T t); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Reactor.Core/flow/IQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Reactor.Core.flow 8 | { 9 | /// 10 | /// The standard queue interface. 11 | /// 12 | /// The value type 13 | public interface IQueue 14 | { 15 | /// 16 | /// Offers the given value and returns true if the queue is not full. 17 | /// 18 | /// The value to enqueue. 19 | /// True if successful, false if the queue is full. 20 | bool Offer(T value); 21 | 22 | /// 23 | /// Tries polling a value into the output value and returns true 24 | /// if successful 25 | /// 26 | /// The output to dequeue the value into 27 | /// True if a value was polled, false if the queue is empty 28 | bool Poll(out T value); 29 | 30 | /// 31 | /// Returns true if the queue is empty. 32 | /// 33 | /// True if the queue is empty. 34 | bool IsEmpty(); 35 | 36 | /// 37 | /// Clears the queue. 38 | /// 39 | void Clear(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Reactor.Core/flow/IQueueSubscription.cs: -------------------------------------------------------------------------------- 1 | using Reactive.Streams; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Reactor.Core.flow 9 | { 10 | /// 11 | /// A combination of an IQueue and an ISubscription to allow queue fusion. 12 | /// 13 | /// The value type in the queue. 14 | public interface IQueueSubscription : IQueue, ISubscription 15 | { 16 | /// 17 | /// Indicate the intent to fuse two subsequent operators. 18 | /// 19 | /// The wanted fusion mode. See the constants. 20 | /// The established fusion mode. See the constants. 21 | int RequestFusion(int mode); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Reactor.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Reactor.Core/parallel/ParallelFromPublishers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.parallel 16 | { 17 | sealed class ParallelFromPublishers : ParallelUnorderedFlux 18 | { 19 | readonly IPublisher[] sources; 20 | 21 | internal ParallelFromPublishers(IPublisher[] sources) 22 | { 23 | this.sources = sources; 24 | } 25 | 26 | public override int Parallelism 27 | { 28 | get 29 | { 30 | return sources.Length; 31 | } 32 | } 33 | 34 | public override void Subscribe(ISubscriber[] subscribers) 35 | { 36 | if (!this.Validate(subscribers)) 37 | { 38 | return; 39 | } 40 | int n = subscribers.Length; 41 | for (int i = 0; i < n; i++) 42 | { 43 | sources[i].Subscribe(subscribers[i]); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Reactor.Core/parallel/ParallelOrderedRunOn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | using System.Runtime.InteropServices; 15 | 16 | namespace Reactor.Core.parallel 17 | { 18 | sealed class ParallelOrderedRunOn : ParallelOrderedFlux 19 | { 20 | readonly ParallelOrderedFlux source; 21 | 22 | readonly Scheduler scheduler; 23 | 24 | readonly int prefetch; 25 | 26 | public override int Parallelism 27 | { 28 | get 29 | { 30 | return source.Parallelism; 31 | } 32 | } 33 | 34 | internal ParallelOrderedRunOn(ParallelOrderedFlux source, Scheduler scheduler, 35 | int prefetch) 36 | { 37 | this.source = source; 38 | this.scheduler = scheduler; 39 | this.prefetch = prefetch; 40 | } 41 | 42 | public override void SubscribeMany(ISubscriber>[] subscribers) 43 | { 44 | if (!this.Validate(subscribers)) 45 | { 46 | return; 47 | } 48 | int n = subscribers.Length; 49 | 50 | var parents = new ISubscriber>[n]; 51 | 52 | for (int i = 0; i < n; i++) 53 | { 54 | var worker = scheduler.CreateWorker(); 55 | var s = subscribers[i]; 56 | if (s is IConditionalSubscriber>) 57 | { 58 | parents[i] = new ParallelUnorderedRunOn> 59 | .ParallelObserveOnConditionalSubscriber( 60 | (IConditionalSubscriber>)s, prefetch, worker); 61 | } 62 | else 63 | { 64 | parents[i] = new ParallelUnorderedRunOn> 65 | .ParallelObserveOnSubscriber(s, prefetch, worker); 66 | } 67 | } 68 | 69 | source.SubscribeMany(parents); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Reactor.Core/parallel/ParallelReduce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | using Reactor.Core.publisher; 15 | 16 | namespace Reactor.Core.parallel 17 | { 18 | sealed class ParallelReduce : ParallelUnorderedFlux 19 | { 20 | readonly IParallelFlux source; 21 | 22 | readonly Func initialFactory; 23 | 24 | readonly Func reducer; 25 | 26 | public override int Parallelism 27 | { 28 | get 29 | { 30 | return source.Parallelism; 31 | } 32 | } 33 | 34 | internal ParallelReduce(IParallelFlux source, Func initialFactory, Func reducer) 35 | { 36 | this.source = source; 37 | this.initialFactory = initialFactory; 38 | this.reducer = reducer; 39 | } 40 | 41 | public override void Subscribe(ISubscriber[] subscribers) 42 | { 43 | if (!this.Validate(subscribers)) 44 | { 45 | return; 46 | } 47 | 48 | int n = subscribers.Length; 49 | var parents = new ISubscriber[n]; 50 | 51 | for (int i = 0; i < n; i++) 52 | { 53 | R accumulator; 54 | 55 | try 56 | { 57 | accumulator = initialFactory(); 58 | } 59 | catch (Exception ex) 60 | { 61 | ExceptionHelper.ThrowIfFatal(ex); 62 | foreach (var s in subscribers) 63 | { 64 | EmptySubscription.Error(s, ex); 65 | } 66 | return; 67 | } 68 | 69 | parents[i] = new PublisherReduceWith.ReduceWithSubscriber(subscribers[i], accumulator, reducer); 70 | } 71 | 72 | source.Subscribe(parents); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherAction: IFlux, IMono 18 | { 19 | readonly Action action; 20 | 21 | public PublisherAction(Action action) 22 | { 23 | this.action = action; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | try 29 | { 30 | action(); 31 | } 32 | catch (Exception ex) 33 | { 34 | ExceptionHelper.ThrowIfFatal(ex); 35 | EmptySubscription.Error(s, ex); 36 | return; 37 | } 38 | EmptySubscription.Complete(s); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherAll.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherAll : IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | readonly Func predicate; 21 | 22 | public PublisherAll(IPublisher source, Func predicate) 23 | { 24 | this.source = source; 25 | this.predicate = predicate; 26 | } 27 | 28 | public void Subscribe(ISubscriber s) 29 | { 30 | source.Subscribe(new AllSubscriber(s, predicate)); 31 | } 32 | 33 | sealed class AllSubscriber : DeferredScalarSubscriber 34 | { 35 | readonly Func predicate; 36 | 37 | bool done; 38 | 39 | public AllSubscriber(ISubscriber actual, Func predicate) : base(actual) 40 | { 41 | this.predicate = predicate; 42 | } 43 | 44 | protected override void OnStart() 45 | { 46 | s.Request(long.MaxValue); 47 | } 48 | 49 | 50 | public override void OnComplete() 51 | { 52 | if (done) 53 | { 54 | return; 55 | } 56 | Complete(true); 57 | } 58 | 59 | public override void OnError(Exception e) 60 | { 61 | if (done) 62 | { 63 | ExceptionHelper.OnErrorDropped(e); 64 | return; 65 | } 66 | done = true; 67 | Error(e); 68 | } 69 | 70 | public override void OnNext(T t) 71 | { 72 | if (done) 73 | { 74 | return; 75 | } 76 | 77 | bool b; 78 | 79 | try 80 | { 81 | b = predicate(t); 82 | } 83 | catch (Exception ex) 84 | { 85 | done = true; 86 | Fail(ex); 87 | return; 88 | } 89 | if (!b) 90 | { 91 | s.Cancel(); 92 | done = true; 93 | Complete(false); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherAny.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherAny : IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | readonly Func predicate; 21 | 22 | public PublisherAny(IPublisher source, Func predicate) 23 | { 24 | this.source = source; 25 | this.predicate = predicate; 26 | } 27 | 28 | public void Subscribe(ISubscriber s) 29 | { 30 | source.Subscribe(new AnySubscriber(s, predicate)); 31 | } 32 | 33 | sealed class AnySubscriber : DeferredScalarSubscriber 34 | { 35 | readonly Func predicate; 36 | 37 | bool done; 38 | 39 | public AnySubscriber(ISubscriber actual, Func predicate) : base(actual) 40 | { 41 | this.predicate = predicate; 42 | } 43 | 44 | protected override void OnStart() 45 | { 46 | s.Request(long.MaxValue); 47 | } 48 | 49 | 50 | public override void OnComplete() 51 | { 52 | if (done) 53 | { 54 | return; 55 | } 56 | Complete(false); 57 | } 58 | 59 | public override void OnError(Exception e) 60 | { 61 | if (done) 62 | { 63 | ExceptionHelper.OnErrorDropped(e); 64 | return; 65 | } 66 | done = true; 67 | Error(e); 68 | } 69 | 70 | public override void OnNext(T t) 71 | { 72 | if (done) 73 | { 74 | return; 75 | } 76 | 77 | bool b; 78 | 79 | try 80 | { 81 | b = predicate(t); 82 | } 83 | catch (Exception ex) 84 | { 85 | done = true; 86 | Fail(ex); 87 | return; 88 | } 89 | if (b) 90 | { 91 | s.Cancel(); 92 | done = true; 93 | Complete(true); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherAsObservable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | /// 18 | /// Wraps an IPublisher and exposes it as an IObservable. 19 | /// 20 | /// 21 | sealed class PublisherAsObservable : IObservable 22 | { 23 | readonly IPublisher source; 24 | 25 | internal PublisherAsObservable(IPublisher source) 26 | { 27 | this.source = source; 28 | } 29 | 30 | public IDisposable Subscribe(IObserver observer) 31 | { 32 | var s = new AsObserver(observer); 33 | 34 | source.Subscribe(s); 35 | 36 | return s; 37 | } 38 | 39 | sealed class AsObserver : ISubscriber, IDisposable 40 | { 41 | readonly IObserver observer; 42 | 43 | ISubscription s; 44 | 45 | bool done; 46 | 47 | internal AsObserver(IObserver observer) 48 | { 49 | this.observer = observer; 50 | } 51 | 52 | public void OnSubscribe(ISubscription s) 53 | { 54 | if (SubscriptionHelper.SetOnce(ref this.s, s)) 55 | { 56 | s.Request(long.MaxValue); 57 | } 58 | } 59 | 60 | public void OnNext(T t) 61 | { 62 | if (done) 63 | { 64 | return; 65 | } 66 | try 67 | { 68 | observer.OnNext(t); 69 | } 70 | catch (Exception ex) 71 | { 72 | ExceptionHelper.ThrowIfFatal(ex); 73 | s.Cancel(); 74 | OnError(ex); 75 | } 76 | } 77 | 78 | public void OnError(Exception e) 79 | { 80 | if (done) 81 | { 82 | ExceptionHelper.OnErrorDropped(e); 83 | return; 84 | } 85 | done = true; 86 | 87 | try 88 | { 89 | observer.OnError(e); 90 | } 91 | catch (Exception ex) 92 | { 93 | ExceptionHelper.ThrowIfFatal(ex); 94 | ExceptionHelper.OnErrorDropped(new AggregateException(e, ex)); 95 | } 96 | } 97 | 98 | public void OnComplete() 99 | { 100 | if (done) 101 | { 102 | return; 103 | } 104 | done = true; 105 | 106 | try 107 | { 108 | observer.OnCompleted(); 109 | } 110 | catch (Exception ex) 111 | { 112 | ExceptionHelper.ThrowOrDrop(ex); 113 | } 114 | } 115 | 116 | public void Dispose() 117 | { 118 | SubscriptionHelper.Cancel(ref s); 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherCallableXMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherCallableXMap 17 | { 18 | /// 19 | /// Applies shortcuts if the source is the empty instance or an ICallable. 20 | /// 21 | /// The source IPublisher. 22 | /// The ISubscriber 23 | /// The function that takes a source value and maps it into an IPublisher. 24 | /// True if the optimizations were applied. 25 | internal static bool CallableXMap(IPublisher source, ISubscriber s, Func> mapper) 26 | { 27 | if (source == PublisherEmpty.Instance) 28 | { 29 | EmptySubscription.Complete(s); 30 | return true; 31 | } 32 | if (source is ICallable) 33 | { 34 | T t; 35 | 36 | try 37 | { 38 | t = (source as ICallable).Value; 39 | } 40 | catch (Exception ex) 41 | { 42 | ExceptionHelper.ThrowIfFatal(ex); 43 | 44 | EmptySubscription.Error(s, ex); 45 | return true; 46 | } 47 | 48 | IPublisher p; 49 | 50 | try 51 | { 52 | p = mapper(t); 53 | } 54 | catch (Exception ex) 55 | { 56 | ExceptionHelper.ThrowIfFatal(ex); 57 | 58 | EmptySubscription.Error(s, ex); 59 | return true; 60 | } 61 | 62 | if (p == null) 63 | { 64 | EmptySubscription.Error(s, new NullReferenceException("The mapper returned a null IPublisher")); 65 | return true; 66 | } 67 | 68 | if (p == PublisherEmpty.Instance) 69 | { 70 | EmptySubscription.Complete(s); 71 | return true; 72 | } 73 | 74 | if (p is ICallable) 75 | { 76 | R r; 77 | 78 | try 79 | { 80 | r = (p as ICallable).Value; 81 | } 82 | catch (Exception ex) 83 | { 84 | ExceptionHelper.ThrowIfFatal(ex); 85 | 86 | EmptySubscription.Error(s, ex); 87 | return true; 88 | } 89 | 90 | s.OnSubscribe(new ScalarSubscription(s, r)); 91 | return true; 92 | } 93 | 94 | p.Subscribe(s); 95 | 96 | return true; 97 | } 98 | 99 | return false; 100 | } 101 | 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherCollect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | using Reactor.Core.subscriber; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherCollect : IMono, IFlux 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly Func collectionSupplier; 22 | 23 | readonly Action collector; 24 | 25 | internal PublisherCollect(IPublisher source, Func collectionSupplier, Action collector) 26 | { 27 | this.source = source; 28 | this.collectionSupplier = collectionSupplier; 29 | this.collector = collector; 30 | } 31 | 32 | public void Subscribe(ISubscriber s) 33 | { 34 | C c; 35 | 36 | try 37 | { 38 | c = collectionSupplier(); 39 | } 40 | catch (Exception ex) 41 | { 42 | ExceptionHelper.ThrowIfFatal(ex); 43 | EmptySubscription.Error(s, ex); 44 | return; 45 | } 46 | 47 | CollectSubscriber parent = new CollectSubscriber(s, c, collector); 48 | 49 | source.Subscribe(parent); 50 | } 51 | 52 | sealed class CollectSubscriber : DeferredScalarSubscriber 53 | { 54 | readonly Action collector; 55 | 56 | internal CollectSubscriber(ISubscriber actual, C collection, Action collector) : base(actual) 57 | { 58 | this.value = collection; 59 | this.collector = collector; 60 | } 61 | 62 | public override void OnComplete() 63 | { 64 | Complete(value); 65 | } 66 | 67 | public override void OnError(Exception e) 68 | { 69 | Error(e); 70 | } 71 | 72 | public override void OnNext(T t) 73 | { 74 | try 75 | { 76 | collector(value, t); 77 | } 78 | catch (Exception ex) 79 | { 80 | Fail(ex); 81 | return; 82 | } 83 | } 84 | 85 | protected override void OnStart() 86 | { 87 | s.Request(long.MaxValue); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherCount.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | using Reactor.Core.subscriber; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherCount : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | public PublisherCount(IPublisher source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | source.Subscribe(new CountSubscriber(s)); 29 | } 30 | 31 | sealed class CountSubscriber : DeferredScalarSubscriber 32 | { 33 | public CountSubscriber(ISubscriber actual) : base(actual) 34 | { 35 | } 36 | 37 | public override void OnComplete() 38 | { 39 | Complete(value); 40 | } 41 | 42 | public override void OnError(Exception e) 43 | { 44 | Error(e); 45 | } 46 | 47 | public override void OnNext(T t) 48 | { 49 | value++; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherDefer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherDefer : IFlux, IMono 17 | { 18 | readonly Func> supplier; 19 | 20 | internal PublisherDefer(Func> supplier) 21 | { 22 | this.supplier = supplier; 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | IPublisher p; 28 | 29 | try 30 | { 31 | p = supplier(); 32 | } 33 | catch (Exception ex) 34 | { 35 | ExceptionHelper.ThrowIfFatal(ex); 36 | EmptySubscription.Error(s, ex); 37 | return; 38 | } 39 | 40 | if (p == null) 41 | { 42 | EmptySubscription.Error(s, new NullReferenceException("The supplier returned a null IPublisher")); 43 | return; 44 | } 45 | 46 | p.Subscribe(s); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherDelay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherDelay : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly TimeSpan delay; 22 | 23 | readonly TimedScheduler scheduler; 24 | 25 | internal PublisherDelay(IPublisher source, TimeSpan delay, TimedScheduler scheduler) 26 | { 27 | this.source = source; 28 | this.delay = delay; 29 | this.scheduler = scheduler; 30 | } 31 | 32 | public void Subscribe(ISubscriber s) 33 | { 34 | source.Subscribe(new DelaySubscriber(s, delay, scheduler.CreateTimedWorker())); 35 | } 36 | 37 | sealed class DelaySubscriber : ISubscriber, ISubscription 38 | { 39 | readonly ISubscriber actual; 40 | 41 | readonly TimeSpan delay; 42 | 43 | readonly TimedWorker worker; 44 | 45 | ISubscription s; 46 | 47 | internal DelaySubscriber(ISubscriber actual, TimeSpan delay, TimedWorker worker) 48 | { 49 | this.actual = actual; 50 | this.delay = delay; 51 | this.worker = worker; 52 | } 53 | 54 | public void Cancel() 55 | { 56 | s.Cancel(); 57 | worker.Dispose(); 58 | } 59 | 60 | public void OnComplete() 61 | { 62 | worker.Schedule(() => 63 | { 64 | actual.OnComplete(); 65 | 66 | worker.Dispose(); 67 | }, delay); 68 | } 69 | 70 | public void OnError(Exception e) 71 | { 72 | worker.Schedule(() => { 73 | actual.OnError(e); 74 | 75 | worker.Dispose(); 76 | }, delay); 77 | } 78 | 79 | public void OnNext(T t) 80 | { 81 | worker.Schedule(() => actual.OnNext(t), delay); 82 | } 83 | 84 | public void OnSubscribe(ISubscription s) 85 | { 86 | if (SubscriptionHelper.Validate(ref this.s, s)) 87 | { 88 | actual.OnSubscribe(this); 89 | } 90 | } 91 | 92 | public void Request(long n) 93 | { 94 | s.Request(n); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherDematerialize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherDematerialize : IFlux 18 | { 19 | readonly IPublisher> source; 20 | 21 | internal PublisherDematerialize(IPublisher> source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | source.Subscribe(new DematerializeSubscriber(s)); 29 | } 30 | 31 | sealed class DematerializeSubscriber : BasicSubscriber, T>, ISubscription 32 | { 33 | ISignal value; 34 | 35 | public DematerializeSubscriber(ISubscriber actual) : base(actual) 36 | { 37 | } 38 | 39 | protected override void AfterSubscribe() 40 | { 41 | s.Request(1); 42 | } 43 | 44 | public override void OnComplete() 45 | { 46 | Complete(); 47 | } 48 | 49 | public override void OnError(Exception e) 50 | { 51 | Error(e); 52 | } 53 | 54 | public override void OnNext(ISignal t) 55 | { 56 | if (done) 57 | { 58 | return; 59 | } 60 | 61 | var s = value; 62 | 63 | if (s != null) 64 | { 65 | if (s.IsNext) 66 | { 67 | actual.OnNext(s.Next); 68 | } 69 | else 70 | if (s.IsError) 71 | { 72 | value = null; 73 | this.s.Cancel(); 74 | Error(s.Error); 75 | return; 76 | } 77 | else 78 | { 79 | this.s.Cancel(); 80 | Complete(); 81 | return; 82 | } 83 | } 84 | 85 | value = t; 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherElementAt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherElementAt : IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly long index; 22 | 23 | readonly T defaultValue; 24 | 25 | readonly bool hasDefault; 26 | 27 | internal PublisherElementAt(IPublisher source, long index, T defaultValue, bool hasDefault) 28 | { 29 | this.source = source; 30 | this.index = index; 31 | this.defaultValue = defaultValue; 32 | this.hasDefault = hasDefault; 33 | } 34 | 35 | public void Subscribe(ISubscriber s) 36 | { 37 | source.Subscribe(new ElementAtSubscriber(s, index, defaultValue, hasDefault)); 38 | } 39 | 40 | sealed class ElementAtSubscriber : DeferredScalarSubscriber 41 | { 42 | readonly long index; 43 | 44 | readonly T defaultValue; 45 | 46 | readonly bool hasDefault; 47 | 48 | long i; 49 | 50 | bool done; 51 | 52 | public ElementAtSubscriber(ISubscriber actual, long index, T defaultValue, bool hasDefault) : base(actual) 53 | { 54 | this.index = index; 55 | this.defaultValue = defaultValue; 56 | this.hasDefault = hasDefault; 57 | } 58 | 59 | public override void OnComplete() 60 | { 61 | if (done) 62 | { 63 | return; 64 | } 65 | done = true; 66 | if (hasDefault) 67 | { 68 | Complete(defaultValue); 69 | } 70 | else 71 | { 72 | Complete(); 73 | } 74 | } 75 | 76 | public override void OnError(Exception e) 77 | { 78 | if (done) 79 | { 80 | ExceptionHelper.OnErrorDropped(e); 81 | return; 82 | } 83 | done = true; 84 | Error(e); 85 | } 86 | 87 | public override void OnNext(T t) 88 | { 89 | long j = i; 90 | if (j == index) 91 | { 92 | s.Cancel(); 93 | done = true; 94 | Complete(t); 95 | } 96 | else 97 | { 98 | i = j + 1; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherEmpty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | 13 | namespace Reactor.Core.publisher 14 | { 15 | sealed class PublisherEmpty : IFlux, IMono 16 | { 17 | internal static readonly PublisherEmpty Instance = new PublisherEmpty(); 18 | 19 | private PublisherEmpty() 20 | { 21 | 22 | } 23 | 24 | public void Subscribe(ISubscriber s) 25 | { 26 | EmptySubscription.Complete(s); 27 | } 28 | 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherError : IFlux, IMono 18 | { 19 | readonly Exception error; 20 | 21 | readonly bool whenRequested; 22 | 23 | internal PublisherError(Exception error, bool whenRequested) 24 | { 25 | this.error = error; 26 | this.whenRequested = whenRequested; 27 | } 28 | 29 | public void Subscribe(ISubscriber s) 30 | { 31 | if (!whenRequested) 32 | { 33 | EmptySubscription.Error(s, error); 34 | } 35 | else 36 | { 37 | s.OnSubscribe(new ErrorSubscription(s, error)); 38 | } 39 | } 40 | 41 | sealed class ErrorSubscription : IQueueSubscription 42 | { 43 | readonly ISubscriber actual; 44 | 45 | readonly Exception error; 46 | 47 | int once; 48 | 49 | int fusionMode; 50 | 51 | public ErrorSubscription(ISubscriber actual, Exception error) 52 | { 53 | this.actual = actual; 54 | this.error = error; 55 | } 56 | 57 | public void Cancel() 58 | { 59 | Volatile.Write(ref once, 1); 60 | } 61 | 62 | public void Clear() 63 | { 64 | // ignored 65 | } 66 | 67 | public bool IsEmpty() 68 | { 69 | throw error; 70 | } 71 | 72 | public bool Offer(T value) 73 | { 74 | return FuseableHelper.DontCallOffer(); 75 | } 76 | 77 | public bool Poll(out T value) 78 | { 79 | throw error; 80 | } 81 | 82 | public void Request(long n) 83 | { 84 | if (SubscriptionHelper.Validate(n)) 85 | { 86 | if (Interlocked.CompareExchange(ref once, 1, 0) == 0) 87 | { 88 | if (fusionMode == FuseableHelper.ASYNC) 89 | { 90 | actual.OnNext(default(T)); 91 | } 92 | else 93 | { 94 | actual.OnError(error); 95 | } 96 | } 97 | } 98 | } 99 | 100 | public int RequestFusion(int mode) 101 | { 102 | fusionMode = mode; 103 | return mode; 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherFirstOrEmpty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherFirstOrEmpty : IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | internal PublisherFirstOrEmpty(IPublisher source) 21 | { 22 | this.source = source; 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | source.Subscribe(new FirstOrEmptySubscriber(s)); 28 | } 29 | 30 | sealed class FirstOrEmptySubscriber : DeferredScalarSubscriber 31 | { 32 | 33 | bool done; 34 | 35 | public FirstOrEmptySubscriber(ISubscriber actual) : base(actual) 36 | { 37 | } 38 | 39 | public override void OnComplete() 40 | { 41 | if (done) 42 | { 43 | return; 44 | } 45 | done = true; 46 | Complete(); 47 | } 48 | 49 | public override void OnError(Exception e) 50 | { 51 | if (done) 52 | { 53 | ExceptionHelper.OnErrorDropped(e); 54 | return; 55 | } 56 | done = true; 57 | Error(e); 58 | } 59 | 60 | public override void OnNext(T t) 61 | { 62 | if (done) 63 | { 64 | return; 65 | } 66 | done = true; 67 | s.Cancel(); 68 | Complete(t); 69 | } 70 | 71 | protected override void OnStart() 72 | { 73 | s.Request(long.MaxValue); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherFromTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherFromTask : IFlux, IMono 18 | { 19 | readonly Task task; 20 | 21 | internal PublisherFromTask(Task task) 22 | { 23 | this.task = task; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | var ts = new TaskSubscription(s); 29 | task.ContinueWith(t => 30 | { 31 | if (t.IsCompleted) 32 | { 33 | ts.Complete(t.Result); 34 | } 35 | else 36 | if (t.IsFaulted) 37 | { 38 | ts.Error(t.Exception); 39 | } 40 | }, ts.ct.Token); 41 | } 42 | 43 | sealed class TaskSubscription : DeferredScalarSubscription 44 | { 45 | internal CancellationTokenSource ct; 46 | 47 | public TaskSubscription(ISubscriber actual) : base(actual) 48 | { 49 | ct = new CancellationTokenSource(); 50 | } 51 | 52 | public override void Cancel() 53 | { 54 | base.Cancel(); 55 | try 56 | { 57 | ct.Cancel(); 58 | } 59 | catch (Exception ex) 60 | { 61 | ExceptionHelper.OnErrorDropped(ex); 62 | } 63 | } 64 | } 65 | } 66 | 67 | sealed class PublisherFromTask : IFlux, IMono 68 | { 69 | readonly Task task; 70 | 71 | internal PublisherFromTask(Task task) 72 | { 73 | this.task = task; 74 | } 75 | 76 | public void Subscribe(ISubscriber s) 77 | { 78 | var ts = new TaskSubscription(s); 79 | task.ContinueWith(t => 80 | { 81 | if (t.IsCompleted) 82 | { 83 | ts.Complete(); 84 | } 85 | else 86 | if (t.IsFaulted) 87 | { 88 | ts.Error(t.Exception); 89 | } 90 | }, ts.ct.Token); 91 | } 92 | 93 | sealed class TaskSubscription : DeferredScalarSubscription 94 | { 95 | internal CancellationTokenSource ct; 96 | 97 | public TaskSubscription(ISubscriber actual) : base(actual) 98 | { 99 | ct = new CancellationTokenSource(); 100 | } 101 | 102 | public override void Cancel() 103 | { 104 | base.Cancel(); 105 | try 106 | { 107 | ct.Cancel(); 108 | } 109 | catch (Exception ex) 110 | { 111 | ExceptionHelper.OnErrorDropped(ex); 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherFunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherFunc : IFlux, IMono, ICallable 17 | { 18 | readonly Func supplier; 19 | 20 | readonly bool nullMeansEmpty; 21 | 22 | public T Value 23 | { 24 | get 25 | { 26 | return supplier(); 27 | } 28 | } 29 | 30 | public PublisherFunc(Func supplier, bool nullMeansEmpty) 31 | { 32 | this.supplier = supplier; 33 | this.nullMeansEmpty = nullMeansEmpty; 34 | } 35 | 36 | public void Subscribe(ISubscriber s) 37 | { 38 | var parent = new FuncSubscription(s); 39 | s.OnSubscribe(parent); 40 | 41 | T v; 42 | try 43 | { 44 | v = supplier(); 45 | } 46 | catch (Exception ex) 47 | { 48 | ExceptionHelper.ThrowIfFatal(ex); 49 | parent.Error(ex); 50 | return; 51 | } 52 | 53 | if (nullMeansEmpty && v == null) 54 | { 55 | s.OnComplete(); 56 | return; 57 | } 58 | 59 | parent.Complete(v); 60 | } 61 | 62 | sealed class FuncSubscription : DeferredScalarSubscription 63 | { 64 | public FuncSubscription(ISubscriber actual) : base(actual) 65 | { 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherHasElements.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherHasElements : IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | internal PublisherHasElements(IPublisher source) 21 | { 22 | this.source = source; 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | source.Subscribe(new HasElementsSubscriber(s)); 28 | } 29 | 30 | sealed class HasElementsSubscriber : DeferredScalarSubscriber 31 | { 32 | bool done; 33 | 34 | public HasElementsSubscriber(ISubscriber actual) : base(actual) 35 | { 36 | 37 | } 38 | 39 | protected override void OnStart() 40 | { 41 | s.Request(long.MaxValue); 42 | } 43 | 44 | public override void OnComplete() 45 | { 46 | if (done) 47 | { 48 | return; 49 | } 50 | done = true; 51 | Complete(false); 52 | } 53 | 54 | public override void OnError(Exception e) 55 | { 56 | if (done) 57 | { 58 | ExceptionHelper.OnErrorDropped(e); 59 | return; 60 | } 61 | done = true; 62 | Error(e); 63 | } 64 | 65 | public override void OnNext(T t) 66 | { 67 | if (done) 68 | { 69 | return; 70 | } 71 | done = true; 72 | s.Cancel(); 73 | Complete(true); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherHide.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherHide : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | internal PublisherHide(IPublisher source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | source.Subscribe(new HideSubscriber(s)); 29 | } 30 | 31 | sealed class HideSubscriber : ISubscriber, ISubscription 32 | { 33 | readonly ISubscriber actual; 34 | 35 | ISubscription s; 36 | 37 | internal HideSubscriber(ISubscriber actual) 38 | { 39 | this.actual = actual; 40 | } 41 | 42 | public void Cancel() 43 | { 44 | s.Cancel(); 45 | } 46 | 47 | public void OnComplete() 48 | { 49 | actual.OnComplete(); 50 | } 51 | 52 | public void OnError(Exception e) 53 | { 54 | actual.OnError(e); 55 | } 56 | 57 | public void OnNext(T t) 58 | { 59 | actual.OnNext(t); 60 | } 61 | 62 | public void OnSubscribe(ISubscription s) 63 | { 64 | this.s = s; 65 | actual.OnSubscribe(this); 66 | } 67 | 68 | public void Request(long n) 69 | { 70 | s.Request(n); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherIgnoreElements.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherIgnoreElements : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | internal PublisherIgnoreElements(IPublisher source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | source.Subscribe(new IgnoreElementsSubscriber(s)); 29 | } 30 | 31 | sealed class IgnoreElementsSubscriber : ISubscriber, IQueueSubscription 32 | { 33 | readonly ISubscriber actual; 34 | 35 | ISubscription s; 36 | 37 | public IgnoreElementsSubscriber(ISubscriber actual) 38 | { 39 | this.actual = actual; 40 | } 41 | 42 | public void Cancel() 43 | { 44 | s.Cancel(); 45 | } 46 | 47 | public void Clear() 48 | { 49 | // always empty 50 | } 51 | 52 | public bool IsEmpty() 53 | { 54 | return true; 55 | } 56 | 57 | public bool Offer(R value) 58 | { 59 | return FuseableHelper.DontCallOffer(); 60 | } 61 | 62 | public void OnComplete() 63 | { 64 | actual.OnComplete(); 65 | } 66 | 67 | public void OnError(Exception e) 68 | { 69 | actual.OnError(e); 70 | } 71 | 72 | public void OnNext(T t) 73 | { 74 | // ignored 75 | } 76 | 77 | public void OnSubscribe(ISubscription s) 78 | { 79 | if (SubscriptionHelper.Validate(ref this.s, s)) 80 | { 81 | s.Request(long.MaxValue); 82 | } 83 | } 84 | 85 | public bool Poll(out R value) 86 | { 87 | value = default(R); 88 | return false; 89 | } 90 | 91 | public void Request(long n) 92 | { 93 | // ignored, always empty 94 | } 95 | 96 | public int RequestFusion(int mode) 97 | { 98 | return mode & FuseableHelper.ASYNC; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherInterval.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherInterval : IFlux 17 | { 18 | readonly TimeSpan initialDelay; 19 | 20 | readonly TimeSpan period; 21 | 22 | readonly TimedScheduler scheduler; 23 | 24 | internal PublisherInterval(TimeSpan initialDelay, TimeSpan period, TimedScheduler scheduler) 25 | { 26 | this.initialDelay = initialDelay; 27 | this.period = period; 28 | this.scheduler = scheduler; 29 | } 30 | 31 | public void Subscribe(ISubscriber s) 32 | { 33 | var parent = new IntervalSubscription(s); 34 | 35 | s.OnSubscribe(parent); 36 | 37 | parent.SetFuture(scheduler.Schedule(parent.Run, initialDelay, period)); 38 | } 39 | } 40 | 41 | sealed class IntervalSubscription : ISubscription 42 | { 43 | 44 | readonly ISubscriber actual; 45 | 46 | long requested; 47 | 48 | IDisposable d; 49 | 50 | long counter; 51 | 52 | internal IntervalSubscription(ISubscriber actual) 53 | { 54 | this.actual = actual; 55 | } 56 | 57 | public void Cancel() 58 | { 59 | DisposableHelper.Dispose(ref d); 60 | } 61 | 62 | public void Request(long n) 63 | { 64 | BackpressureHelper.ValidateAndAddCap(ref requested, n); 65 | } 66 | 67 | internal void Run() 68 | { 69 | if (Volatile.Read(ref requested) != 0L) 70 | { 71 | actual.OnNext(counter++); 72 | 73 | BackpressureHelper.Produced(ref requested, 1); 74 | } 75 | else 76 | { 77 | actual.OnError(BackpressureHelper.MissingBackpressureException()); 78 | } 79 | } 80 | 81 | internal void SetFuture(IDisposable d) 82 | { 83 | DisposableHelper.Set(ref this.d, d); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherJust.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | /// 17 | /// A constant scalar source. 18 | /// 19 | /// 20 | /// It is based on IMono to facilitate easy reuse for Flux and Mono extension methods. 21 | /// 22 | /// The value type 23 | internal sealed class PublisherJust : IFlux, IMono, IScalarCallable 24 | { 25 | readonly T value; 26 | 27 | internal PublisherJust(T value) 28 | { 29 | this.value = value; 30 | } 31 | 32 | public T Value 33 | { 34 | get 35 | { 36 | return value; 37 | } 38 | } 39 | 40 | public void Subscribe(ISubscriber s) 41 | { 42 | s.OnSubscribe(new ScalarSubscription(s, value)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherLast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherLast : IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | internal PublisherLast(IPublisher source) 21 | { 22 | this.source = source; 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | source.Subscribe(new LastSubscriber(s)); 28 | } 29 | 30 | sealed class LastSubscriber : DeferredScalarSubscriber 31 | { 32 | 33 | bool hasValue; 34 | 35 | public LastSubscriber(ISubscriber actual) : base(actual) 36 | { 37 | } 38 | 39 | protected override void OnStart() 40 | { 41 | s.Request(long.MaxValue); 42 | } 43 | 44 | public override void OnComplete() 45 | { 46 | if (hasValue) 47 | { 48 | Complete(value); 49 | } 50 | else 51 | { 52 | Error(new IndexOutOfRangeException("The source sequence is empty.")); 53 | } 54 | } 55 | 56 | public override void OnError(Exception e) 57 | { 58 | Error(e); 59 | } 60 | 61 | public override void OnNext(T t) 62 | { 63 | hasValue = true; 64 | value = t; 65 | } 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherMaterialize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherMaterialize : IFlux> 18 | { 19 | readonly IPublisher source; 20 | 21 | internal PublisherMaterialize(IPublisher source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber> s) 27 | { 28 | source.Subscribe(new MaterializeSubscriber(s)); 29 | } 30 | 31 | sealed class MaterializeSubscriber : BasicSinglePostCompleteSubscriber> 32 | { 33 | public MaterializeSubscriber(ISubscriber> actual) : base(actual) 34 | { 35 | } 36 | 37 | public override void OnComplete() 38 | { 39 | Complete(SignalHelper.Complete()); 40 | } 41 | 42 | public override void OnError(Exception e) 43 | { 44 | Complete(SignalHelper.Error(e)); 45 | } 46 | 47 | public override void OnNext(T t) 48 | { 49 | produced++; 50 | actual.OnNext(SignalHelper.Next(t)); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherMergeArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherMergeArray : IFlux 17 | { 18 | readonly IPublisher[] sources; 19 | 20 | readonly bool delayErrors; 21 | 22 | readonly int maxConcurrency; 23 | 24 | readonly int prefetch; 25 | 26 | internal PublisherMergeArray(IPublisher[] sources, bool delayErrors, int maxConcurrency, int prefetch) 27 | { 28 | this.sources = sources; 29 | this.delayErrors = delayErrors; 30 | this.maxConcurrency = maxConcurrency; 31 | this.prefetch = prefetch; 32 | } 33 | 34 | internal PublisherMergeArray MergeWith(IPublisher other, bool delayError) 35 | { 36 | if (delayError != this.delayErrors) 37 | { 38 | return new PublisherMergeArray(new IPublisher[] { this, other }, delayError, 2, prefetch); 39 | } 40 | var a = MultiSourceHelper.AppendLast(sources, other); 41 | 42 | return new PublisherMergeArray(a, delayErrors, maxConcurrency != int.MaxValue ? maxConcurrency + 1 : int.MaxValue, prefetch); 43 | } 44 | 45 | public void Subscribe(ISubscriber s) 46 | { 47 | var parent = new PublisherFlatMap, T>.FlatMapSubscriber(s, v => v, delayErrors, maxConcurrency, prefetch); 48 | parent.OnSubscribe(new PublisherArray>.ArraySubscription(parent, sources)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherNever.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherNever : IFlux, IMono 17 | { 18 | internal static readonly PublisherNever Instance = new PublisherNever(); 19 | 20 | private PublisherNever() 21 | { 22 | 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | s.OnSubscribe(NeverSubscription.Instance); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherReduce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherReduce : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly Func reducer; 22 | 23 | internal PublisherReduce(IPublisher source, Func reducer) 24 | { 25 | this.source = source; 26 | this.reducer = reducer; 27 | } 28 | 29 | public void Subscribe(ISubscriber s) 30 | { 31 | source.Subscribe(new ReduceSubscriber(s, reducer)); 32 | } 33 | 34 | sealed class ReduceSubscriber : DeferredScalarSubscriber 35 | { 36 | readonly Func reducer; 37 | 38 | bool hasValue; 39 | 40 | public ReduceSubscriber(ISubscriber actual, Func reducer) : base(actual) 41 | { 42 | this.reducer = reducer; 43 | } 44 | 45 | protected override void OnStart() 46 | { 47 | s.Request(long.MaxValue); 48 | } 49 | 50 | public override void OnComplete() 51 | { 52 | if (hasValue) 53 | { 54 | Complete(value); 55 | } 56 | else 57 | { 58 | actual.OnComplete(); 59 | } 60 | } 61 | 62 | public override void OnError(Exception e) 63 | { 64 | value = default(T); 65 | actual.OnError(e); 66 | } 67 | 68 | public override void OnNext(T t) 69 | { 70 | if (!hasValue) 71 | { 72 | value = t; 73 | hasValue = true; 74 | } 75 | else 76 | { 77 | try 78 | { 79 | value = reducer(value, t); 80 | } 81 | catch (Exception ex) 82 | { 83 | Fail(ex); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherReduceWith.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherReduceWith : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly Func initialSupplier; 22 | 23 | readonly Func reducer; 24 | 25 | internal PublisherReduceWith(IPublisher source, Func initialSupplier, Func reducer) 26 | { 27 | this.source = source; 28 | this.reducer = reducer; 29 | this.initialSupplier = initialSupplier; 30 | } 31 | 32 | public void Subscribe(ISubscriber s) 33 | { 34 | A accumulator; 35 | 36 | try 37 | { 38 | accumulator = initialSupplier(); 39 | } 40 | catch (Exception ex) 41 | { 42 | ExceptionHelper.ThrowIfFatal(ex); 43 | EmptySubscription.Error(s, ex); 44 | return; 45 | } 46 | 47 | source.Subscribe(new ReduceWithSubscriber(s, accumulator, reducer)); 48 | } 49 | 50 | internal sealed class ReduceWithSubscriber : DeferredScalarSubscriber 51 | { 52 | readonly Func reducer; 53 | 54 | public ReduceWithSubscriber(ISubscriber actual, A accumulator, Func reducer) : base(actual) 55 | { 56 | this.value = accumulator; 57 | this.reducer = reducer; 58 | } 59 | 60 | protected override void OnStart() 61 | { 62 | s.Request(long.MaxValue); 63 | } 64 | 65 | public override void OnComplete() 66 | { 67 | Complete(value); 68 | } 69 | 70 | public override void OnError(Exception e) 71 | { 72 | value = default(A); 73 | actual.OnError(e); 74 | } 75 | 76 | public override void OnNext(T t) 77 | { 78 | try 79 | { 80 | value = reducer(value, t); 81 | } 82 | catch (Exception ex) 83 | { 84 | Fail(ex); 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherScan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherScan : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly Func scanner; 22 | 23 | internal PublisherScan(IPublisher source, Func scanner) 24 | { 25 | this.source = source; 26 | this.scanner = scanner; 27 | } 28 | 29 | public void Subscribe(ISubscriber s) 30 | { 31 | source.Subscribe(new ScanSubscriber(s, scanner)); 32 | } 33 | 34 | sealed class ScanSubscriber : BasicSubscriber 35 | { 36 | readonly Func scanner; 37 | 38 | T value; 39 | 40 | bool hasValue; 41 | 42 | public ScanSubscriber(ISubscriber actual, Func scanner) : base(actual) 43 | { 44 | this.scanner = scanner; 45 | } 46 | 47 | public override void OnComplete() 48 | { 49 | actual.OnComplete(); 50 | } 51 | 52 | public override void OnError(Exception e) 53 | { 54 | value = default(T); 55 | actual.OnError(e); 56 | } 57 | 58 | public override void OnNext(T t) 59 | { 60 | if (!hasValue) 61 | { 62 | hasValue = true; 63 | value = t; 64 | actual.OnNext(t); 65 | } 66 | else 67 | { 68 | T v; 69 | try 70 | { 71 | v = scanner(value, t); 72 | value = v; 73 | } 74 | catch (Exception ex) 75 | { 76 | Fail(ex); 77 | return; 78 | } 79 | 80 | actual.OnNext(v); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherScanWith.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherScanWith : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly Func initialSupplier; 22 | 23 | readonly Func scanner; 24 | 25 | internal PublisherScanWith(IPublisher source, Func initialSupplier, Func scanner) 26 | { 27 | this.source = source; 28 | this.initialSupplier = initialSupplier; 29 | this.scanner = scanner; 30 | } 31 | 32 | public void Subscribe(ISubscriber s) 33 | { 34 | A accumulator; 35 | 36 | try 37 | { 38 | accumulator = initialSupplier(); 39 | } 40 | catch (Exception ex) 41 | { 42 | ExceptionHelper.ThrowIfFatal(ex); 43 | EmptySubscription.Error(s, ex); 44 | return; 45 | } 46 | source.Subscribe(new ScanWithSubscriber(s, accumulator, scanner)); 47 | } 48 | 49 | sealed class ScanWithSubscriber : BasicSinglePostCompleteSubscriber 50 | { 51 | readonly Func scanner; 52 | 53 | A value; 54 | 55 | public ScanWithSubscriber(ISubscriber actual, A initial, Func scanner) : base(actual) 56 | { 57 | this.scanner = scanner; 58 | this.value = initial; 59 | } 60 | 61 | public override void OnComplete() 62 | { 63 | Complete(value); 64 | } 65 | 66 | public override void OnError(Exception e) 67 | { 68 | value = default(A); 69 | actual.OnError(e); 70 | } 71 | 72 | public override void OnNext(T t) 73 | { 74 | produced++; 75 | 76 | var v = value; 77 | actual.OnNext(v); 78 | 79 | try 80 | { 81 | value = scanner(v, t); 82 | } 83 | catch (Exception ex) 84 | { 85 | Fail(ex); 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherTakeLast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherTakeLast : IFlux 18 | { 19 | readonly IPublisher source; 20 | 21 | readonly long n; 22 | 23 | internal PublisherTakeLast(IPublisher source, long n) 24 | { 25 | this.source = source; 26 | this.n = n; 27 | } 28 | 29 | public void Subscribe(ISubscriber s) 30 | { 31 | source.Subscribe(new TakeLastSubscriber(s, n)); 32 | } 33 | 34 | sealed class TakeLastSubscriber : ISubscriber, ISubscription 35 | { 36 | readonly ISubscriber actual; 37 | 38 | readonly long n; 39 | 40 | readonly IQueue queue; 41 | 42 | ISubscription s; 43 | 44 | long size; 45 | 46 | long requested; 47 | 48 | bool cancelled; 49 | 50 | internal TakeLastSubscriber(ISubscriber actual, long n) 51 | { 52 | this.actual = actual; 53 | this.n = n; 54 | this.queue = new ArrayQueue(); 55 | } 56 | 57 | public void Cancel() 58 | { 59 | Volatile.Write(ref cancelled, true); 60 | s.Cancel(); 61 | } 62 | 63 | public void OnComplete() 64 | { 65 | BackpressureHelper.PostComplete(ref requested, actual, queue, ref cancelled); 66 | } 67 | 68 | public void OnError(Exception e) 69 | { 70 | queue.Clear(); 71 | actual.OnError(e); 72 | } 73 | 74 | public void OnNext(T t) 75 | { 76 | long z = size; 77 | if (z == n) 78 | { 79 | T u; 80 | queue.Poll(out u); 81 | queue.Offer(t); 82 | } 83 | else 84 | { 85 | queue.Offer(t); 86 | size = z + 1; 87 | } 88 | } 89 | 90 | public void OnSubscribe(ISubscription s) 91 | { 92 | if (SubscriptionHelper.Validate(ref this.s, s)) 93 | { 94 | actual.OnSubscribe(this); 95 | 96 | s.Request(long.MaxValue); 97 | } 98 | } 99 | 100 | public void Request(long n) 101 | { 102 | if (SubscriptionHelper.Validate(n)) 103 | { 104 | if (!BackpressureHelper.PostCompleteRequest(ref requested, n, actual, queue, ref cancelled)) 105 | { 106 | s.Request(n); 107 | } 108 | } 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherTakeLastOne.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | sealed class PublisherTakeLastOne : IFlux, IMono 18 | { 19 | readonly IPublisher source; 20 | 21 | internal PublisherTakeLastOne(IPublisher source) 22 | { 23 | this.source = source; 24 | } 25 | 26 | public void Subscribe(ISubscriber s) 27 | { 28 | source.Subscribe(new TakeLastOne(s)); 29 | } 30 | 31 | sealed class TakeLastOne : DeferredScalarSubscriber 32 | { 33 | 34 | bool hasValue; 35 | 36 | public TakeLastOne(ISubscriber actual) : base(actual) 37 | { 38 | } 39 | 40 | protected override void OnStart() 41 | { 42 | s.Request(long.MaxValue); 43 | } 44 | 45 | public override void OnComplete() 46 | { 47 | if (hasValue) 48 | { 49 | Complete(value); 50 | } 51 | else 52 | { 53 | Complete(); 54 | } 55 | } 56 | 57 | public override void OnError(Exception e) 58 | { 59 | value = default(T); 60 | Error(e); 61 | } 62 | 63 | public override void OnNext(T t) 64 | { 65 | if (!hasValue) 66 | { 67 | hasValue = true; 68 | } 69 | value = t; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherTck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.publisher 16 | { 17 | /// 18 | /// Wrapper that makes sure the TCK's misbehaviors are handled according to the 19 | /// TCK's expectations. 20 | /// 21 | /// The value type 22 | sealed class PublisherTck : IFlux, IMono 23 | { 24 | readonly IPublisher source; 25 | 26 | internal PublisherTck(IPublisher source) 27 | { 28 | this.source = source; 29 | } 30 | 31 | public void Subscribe(ISubscriber subscriber) 32 | { 33 | if (subscriber == null) 34 | { 35 | throw new ArgumentNullException(nameof(subscriber), "§1.9 violated: Subscribe(null) not allowed"); 36 | } 37 | source.Subscribe(new TckSubscriber(subscriber)); 38 | } 39 | 40 | sealed class TckSubscriber : ISubscriber, ISubscription 41 | { 42 | readonly ISubscriber actual; 43 | 44 | HalfSerializerStruct serializer; 45 | 46 | ISubscription s; 47 | 48 | internal TckSubscriber(ISubscriber actual) 49 | { 50 | this.actual = actual; 51 | } 52 | 53 | public void OnSubscribe(ISubscription subscription) 54 | { 55 | if (SubscriptionHelper.Validate(ref this.s, subscription)) 56 | { 57 | this.s = subscription; 58 | 59 | actual.OnSubscribe(this); 60 | } 61 | } 62 | 63 | public void OnNext(T element) 64 | { 65 | serializer.OnNext(actual, element); 66 | } 67 | 68 | public void OnError(Exception cause) 69 | { 70 | serializer.OnError(actual, cause); 71 | } 72 | 73 | public void OnComplete() 74 | { 75 | serializer.OnComplete(actual); 76 | } 77 | 78 | public void Request(long n) 79 | { 80 | if (n <= 0) 81 | { 82 | OnError(new ArgumentException("§3.9 violated: non-positive request amount")); 83 | } else 84 | { 85 | s.Request(n); 86 | } 87 | } 88 | 89 | public void Cancel() 90 | { 91 | s.Cancel(); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Reactor.Core/publisher/PublisherWrap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.publisher 15 | { 16 | sealed class PublisherWrap : IFlux, IMono 17 | { 18 | readonly IPublisher source; 19 | 20 | internal PublisherWrap(IPublisher source) 21 | { 22 | this.source = source; 23 | } 24 | 25 | public void Subscribe(ISubscriber s) 26 | { 27 | source.Subscribe(s); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Reactor.Core/scheduler/ImmediateScheduler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.scheduler 16 | { 17 | /// 18 | /// A basic scheduler that executes actions immediately on the caller thread. 19 | /// Useful in conjunction with 20 | /// to rebatch downstream requests. 21 | /// 22 | public sealed class ImmediateScheduler : Scheduler, Worker 23 | { 24 | static readonly ImmediateScheduler INSTANCE = new ImmediateScheduler(); 25 | 26 | /// 27 | /// Returns the singleton instance of this scheduler. 28 | /// 29 | public static ImmediateScheduler Instance { get { return INSTANCE; } } 30 | 31 | /// 32 | public Worker CreateWorker() 33 | { 34 | return this; 35 | } 36 | 37 | /// 38 | public void Dispose() 39 | { 40 | // ignored 41 | } 42 | 43 | /// 44 | public IDisposable Schedule(Action task) 45 | { 46 | task(); 47 | return DisposableHelper.Disposed; 48 | } 49 | 50 | /// 51 | public void Shutdown() 52 | { 53 | // ignored 54 | } 55 | 56 | /// 57 | public void Start() 58 | { 59 | // ignored 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Reactor.Core/subscriber/CallbackSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.subscriber 15 | { 16 | internal sealed class CallbackSubscriber : ISubscriber, IDisposable 17 | { 18 | readonly Action onNext; 19 | 20 | readonly Action onError; 21 | 22 | readonly Action onComplete; 23 | 24 | ISubscription s; 25 | 26 | bool done; 27 | 28 | internal CallbackSubscriber(Action onNext, Action onError, Action onComplete) 29 | { 30 | this.onNext = onNext; 31 | this.onError = onError; 32 | this.onComplete = onComplete; 33 | } 34 | 35 | public void OnSubscribe(ISubscription s) 36 | { 37 | if (SubscriptionHelper.SetOnce(ref this.s, s)) 38 | { 39 | s.Request(long.MaxValue); 40 | } 41 | } 42 | 43 | public void OnNext(T t) 44 | { 45 | try 46 | { 47 | onNext(t); 48 | } catch (Exception ex) 49 | { 50 | ExceptionHelper.ThrowIfFatal(ex); 51 | s.Cancel(); 52 | OnError(ex); 53 | return; 54 | } 55 | } 56 | 57 | public void OnError(Exception e) 58 | { 59 | if (done) 60 | { 61 | ExceptionHelper.OnErrorDropped(e); 62 | return; 63 | } 64 | done = true; 65 | 66 | try 67 | { 68 | onError(e); 69 | } 70 | catch (Exception ex) 71 | { 72 | ExceptionHelper.ThrowIfFatal(ex); 73 | ExceptionHelper.OnErrorDropped(new AggregateException(e, ex)); 74 | } 75 | } 76 | 77 | public void OnComplete() 78 | { 79 | if (done) 80 | { 81 | return; 82 | } 83 | done = true; 84 | try 85 | { 86 | onComplete(); 87 | } 88 | catch (Exception ex) 89 | { 90 | ExceptionHelper.ThrowIfFatal(ex); 91 | ExceptionHelper.OnErrorDropped(ex); 92 | } 93 | } 94 | 95 | public void Dispose() 96 | { 97 | SubscriptionHelper.Cancel(ref s); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Reactor.Core/subscriber/DeferredScalarSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.subscriber 15 | { 16 | /// 17 | /// A subscriber that takes values and produces a single output in a fuseable, 18 | /// backpressure aware manner. 19 | /// 20 | /// The input value type 21 | /// The single output value type 22 | public abstract class DeferredScalarSubscriber : DeferredScalarSubscription, ISubscriber 23 | { 24 | /// 25 | /// The ISubscription to the upstream. 26 | /// 27 | protected ISubscription s; 28 | 29 | /// 30 | /// Constructs an instance with the given actual downstream subscriber. 31 | /// 32 | /// The downstream subscriber 33 | public DeferredScalarSubscriber(ISubscriber actual) : base(actual) 34 | { 35 | } 36 | 37 | /// 38 | public abstract void OnComplete(); 39 | 40 | /// 41 | public abstract void OnError(Exception e); 42 | 43 | /// 44 | public abstract void OnNext(T t); 45 | 46 | /// 47 | public void OnSubscribe(ISubscription s) 48 | { 49 | if (SubscriptionHelper.Validate(ref this.s, s)) 50 | { 51 | actual.OnSubscribe(this); 52 | 53 | OnStart(); 54 | } 55 | } 56 | 57 | /// 58 | /// Called after this instance has been sent to downstream via OnSubscribe. 59 | /// 60 | protected virtual void OnStart() 61 | { 62 | 63 | } 64 | 65 | /// 66 | public override void Cancel() 67 | { 68 | base.Cancel(); 69 | s.Cancel(); 70 | } 71 | 72 | /// 73 | /// Set the done flag and signal the exception. 74 | /// 75 | /// The exception to signal 76 | public override void Error(Exception ex) 77 | { 78 | if (Volatile.Read(ref state) == CANCELLED) 79 | { 80 | ExceptionHelper.OnErrorDropped(ex); 81 | return; 82 | } 83 | base.Cancel(); 84 | base.Error(ex); 85 | } 86 | 87 | /// 88 | /// Rethrow the exception if fatal, otherwise cancel the subscription 89 | /// and signal the exception via . 90 | /// 91 | /// The exception to check and signal 92 | protected void Fail(Exception ex) 93 | { 94 | ExceptionHelper.ThrowIfFatal(ex); 95 | s.Cancel(); 96 | OnError(ex); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Reactor.Core/subscriber/TaskCompleteSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.subscriber 16 | { 17 | sealed class TaskCompleteSubscriber : ISubscriber, IDisposable 18 | { 19 | readonly TaskCompletionSource tcs = new TaskCompletionSource(); 20 | 21 | ISubscription s; 22 | 23 | public void OnComplete() 24 | { 25 | tcs.TrySetResult(null); 26 | } 27 | 28 | public void OnError(Exception e) 29 | { 30 | tcs.TrySetException(e); 31 | } 32 | 33 | public void OnNext(T t) 34 | { 35 | // values ignored 36 | } 37 | 38 | public void OnSubscribe(ISubscription s) 39 | { 40 | if (SubscriptionHelper.SetOnce(ref this.s, s)) 41 | { 42 | s.Request(long.MaxValue); 43 | } 44 | } 45 | 46 | public void Dispose() 47 | { 48 | SubscriptionHelper.Cancel(ref s); 49 | } 50 | 51 | 52 | internal Task Task() 53 | { 54 | return tcs.Task; 55 | } 56 | 57 | internal Task Task(CancellationToken token) 58 | { 59 | token.Register(this.Dispose); 60 | return tcs.Task; 61 | } 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Reactor.Core/subscriber/TaskFirstSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.subscriber 16 | { 17 | sealed class TaskFirstSubscriber : ISubscriber, IDisposable 18 | { 19 | readonly TaskCompletionSource tcs = new TaskCompletionSource(); 20 | 21 | ISubscription s; 22 | 23 | bool hasValue; 24 | 25 | public void OnComplete() 26 | { 27 | if (!hasValue) 28 | { 29 | tcs.TrySetException(new IndexOutOfRangeException("The upstream didn't produce any value.")); 30 | } 31 | } 32 | 33 | public void OnError(Exception e) 34 | { 35 | if (hasValue) 36 | { 37 | ExceptionHelper.OnErrorDropped(e); 38 | return; 39 | } 40 | tcs.TrySetException(e); 41 | } 42 | 43 | public void OnNext(T t) 44 | { 45 | if (hasValue) 46 | { 47 | return; 48 | } 49 | hasValue = true; 50 | s.Cancel(); 51 | tcs.TrySetResult(t); 52 | } 53 | 54 | public void OnSubscribe(ISubscription s) 55 | { 56 | if (SubscriptionHelper.SetOnce(ref this.s, s)) 57 | { 58 | s.Request(long.MaxValue); 59 | } 60 | } 61 | 62 | public void Dispose() 63 | { 64 | SubscriptionHelper.Cancel(ref s); 65 | } 66 | 67 | 68 | internal Task Task() 69 | { 70 | return tcs.Task; 71 | } 72 | 73 | internal Task Task(CancellationToken token) 74 | { 75 | token.Register(this.Dispose); 76 | return tcs.Task; 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Reactor.Core/subscriber/TaskLastSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.subscriber 16 | { 17 | sealed class TaskLastSubscriber : ISubscriber, IDisposable 18 | { 19 | readonly TaskCompletionSource tcs = new TaskCompletionSource(); 20 | 21 | ISubscription s; 22 | 23 | bool hasValue; 24 | 25 | T value; 26 | 27 | public void OnComplete() 28 | { 29 | if (!hasValue) 30 | { 31 | tcs.TrySetException(new IndexOutOfRangeException("The upstream didn't produce any value.")); 32 | } 33 | else 34 | { 35 | tcs.TrySetResult(value); 36 | } 37 | } 38 | 39 | public void OnError(Exception e) 40 | { 41 | tcs.TrySetException(e); 42 | } 43 | 44 | public void OnNext(T t) 45 | { 46 | hasValue = true; 47 | value = t; 48 | } 49 | 50 | public void OnSubscribe(ISubscription s) 51 | { 52 | if (SubscriptionHelper.SetOnce(ref this.s, s)) 53 | { 54 | s.Request(long.MaxValue); 55 | } 56 | } 57 | 58 | public void Dispose() 59 | { 60 | SubscriptionHelper.Cancel(ref s); 61 | } 62 | 63 | internal Task Task() 64 | { 65 | return tcs.Task; 66 | } 67 | 68 | internal Task Task(CancellationToken token) 69 | { 70 | token.Register(this.Dispose); 71 | return tcs.Task; 72 | } 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Reactor.Core/subscription/BasicRejectingSubscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.subscriber 16 | { 17 | /// 18 | /// A IQueueuSubscription that reject all fusion. 19 | /// 20 | /// The output value type 21 | internal abstract class BasicRejectingSubscription : IQueueSubscription 22 | { 23 | public abstract void Cancel(); 24 | 25 | public void Clear() 26 | { 27 | // ignored 28 | } 29 | 30 | public bool IsEmpty() 31 | { 32 | return false; 33 | } 34 | 35 | public bool Offer(T value) 36 | { 37 | return FuseableHelper.DontCallOffer(); 38 | } 39 | 40 | public bool Poll(out T value) 41 | { 42 | value = default(T); 43 | return false; 44 | } 45 | 46 | public abstract void Request(long n); 47 | 48 | public int RequestFusion(int mode) 49 | { 50 | return FuseableHelper.NONE; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Reactor.Core/subscription/EmptySubscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core.subscription 13 | { 14 | /// 15 | /// Represents an empty subscription that ignores requests and cancellation. 16 | /// 17 | /// The value type (no value is emitted) 18 | public sealed class EmptySubscription : IQueueSubscription 19 | { 20 | 21 | private EmptySubscription() 22 | { 23 | 24 | } 25 | 26 | private static readonly EmptySubscription INSTANCE = new EmptySubscription(); 27 | 28 | /// 29 | /// Returns the singleton instance of the EmptySubscription class. 30 | /// 31 | public static EmptySubscription Instance { get { return INSTANCE; } } 32 | 33 | /// 34 | /// Sets the empty instance on the ISubscriber and calls OnError with the Exception. 35 | /// 36 | /// The target ISubscriber 37 | /// The exception to send 38 | public static void Error(ISubscriber s, Exception ex) 39 | { 40 | s.OnSubscribe(Instance); 41 | s.OnError(ex); 42 | } 43 | 44 | /// 45 | /// Sets the empty instance on the ISubscriber and calls OnComplete. 46 | /// 47 | /// The target ISubscriber 48 | public static void Complete(ISubscriber s) 49 | { 50 | s.OnSubscribe(Instance); 51 | s.OnComplete(); 52 | } 53 | 54 | /// 55 | public void Cancel() 56 | { 57 | // deliberately ignored 58 | } 59 | 60 | /// 61 | public void Clear() 62 | { 63 | // deliberately ignored 64 | } 65 | 66 | /// 67 | public bool IsEmpty() 68 | { 69 | return true; 70 | } 71 | 72 | /// 73 | public bool Offer(T value) 74 | { 75 | return FuseableHelper.DontCallOffer(); 76 | } 77 | 78 | /// 79 | public bool Poll(out T value) 80 | { 81 | value = default(T); 82 | return false; 83 | } 84 | 85 | /// 86 | public void Request(long n) 87 | { 88 | // deliberately ignored 89 | } 90 | 91 | /// 92 | public int RequestFusion(int mode) 93 | { 94 | return mode & FuseableHelper.ASYNC; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Reactor.Core/subscription/NeverSubscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | 12 | namespace Reactor.Core.subscription 13 | { 14 | /// 15 | /// Represents an empty subscription that ignores requests and cancellation. 16 | /// 17 | /// The value type (no value is emitted) 18 | public sealed class NeverSubscription : IQueueSubscription 19 | { 20 | 21 | private NeverSubscription() 22 | { 23 | 24 | } 25 | 26 | private static readonly NeverSubscription INSTANCE = new NeverSubscription(); 27 | 28 | /// 29 | /// Returns the singleton instance of the EmptySubscription class. 30 | /// 31 | public static NeverSubscription Instance { get { return INSTANCE; } } 32 | 33 | /// 34 | public void Cancel() 35 | { 36 | // deliberately ignored 37 | } 38 | 39 | /// 40 | public void Clear() 41 | { 42 | // deliberately ignored 43 | } 44 | 45 | /// 46 | public bool IsEmpty() 47 | { 48 | // deliberately ignored 49 | return true; 50 | } 51 | 52 | /// 53 | public bool Offer(T value) 54 | { 55 | return FuseableHelper.DontCallOffer(); 56 | } 57 | 58 | /// 59 | public bool Poll(out T value) 60 | { 61 | value = default(T); 62 | return false; 63 | } 64 | 65 | /// 66 | public void Request(long n) 67 | { 68 | // deliberately ignored 69 | } 70 | 71 | /// 72 | public int RequestFusion(int mode) 73 | { 74 | if ((mode & FuseableHelper.ASYNC) != 0) 75 | { 76 | return FuseableHelper.ASYNC; 77 | } 78 | return FuseableHelper.NONE; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Reactor.Core/subscription/ScalarSubscription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.subscription 15 | { 16 | /// 17 | /// A fuseable subscription that emits a single value on request or poll. 18 | /// 19 | /// The value type 20 | public sealed class ScalarSubscription : IQueueSubscription 21 | { 22 | readonly ISubscriber actual; 23 | 24 | readonly T value; 25 | 26 | int state; 27 | 28 | static readonly int READY = 0; 29 | 30 | static readonly int REQUESTED = 1; 31 | 32 | static readonly int CANCELLED = 2; 33 | 34 | /// 35 | /// Constructs a ScalarSubscription with the target ISubscriber and value to 36 | /// emit on request. 37 | /// 38 | /// The target ISubscriber 39 | /// The value to emit 40 | public ScalarSubscription(ISubscriber actual, T value) 41 | { 42 | if (value == null) 43 | { 44 | throw new ArgumentNullException("value"); 45 | } 46 | this.actual = actual; 47 | this.value = value; 48 | } 49 | 50 | /// 51 | public int RequestFusion(int mode) 52 | { 53 | if ((mode & FuseableHelper.SYNC) != 0) 54 | { 55 | return FuseableHelper.SYNC; 56 | } 57 | return FuseableHelper.NONE; 58 | } 59 | 60 | /// 61 | public bool Offer(T value) 62 | { 63 | return FuseableHelper.DontCallOffer(); 64 | } 65 | 66 | /// 67 | public bool Poll(out T value) 68 | { 69 | int s = state; 70 | if (s == READY) 71 | { 72 | state = REQUESTED; 73 | value = this.value; 74 | return true; 75 | } 76 | value = default(T); 77 | return false; 78 | } 79 | 80 | /// 81 | public bool IsEmpty() 82 | { 83 | return state != READY; 84 | } 85 | 86 | /// 87 | public void Clear() 88 | { 89 | state = REQUESTED; 90 | } 91 | 92 | /// 93 | public void Request(long n) 94 | { 95 | if (SubscriptionHelper.Validate(n)) 96 | { 97 | if (Interlocked.CompareExchange(ref state, REQUESTED, READY) == READY) 98 | { 99 | actual.OnNext(value); 100 | if (Volatile.Read(ref state) != CANCELLED) 101 | { 102 | actual.OnComplete(); 103 | } 104 | } 105 | } 106 | } 107 | 108 | /// 109 | public void Cancel() 110 | { 111 | Volatile.Write(ref state, CANCELLED); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Reactor.Core/util/ArrayQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core.flow; 9 | using Reactor.Core.subscriber; 10 | using Reactor.Core.subscription; 11 | using Reactor.Core.util; 12 | using System.Threading; 13 | 14 | namespace Reactor.Core.util 15 | { 16 | sealed class ArrayQueue : IQueue 17 | { 18 | internal T[] array; 19 | 20 | internal int mask; 21 | 22 | internal long consumerIndex; 23 | 24 | internal long producerIndex; 25 | 26 | public void Clear() 27 | { 28 | QueueHelper.Clear(this); 29 | } 30 | 31 | public bool IsEmpty() 32 | { 33 | return producerIndex == consumerIndex; 34 | } 35 | 36 | public bool Offer(T value) 37 | { 38 | T[] a = array; 39 | int m = mask; 40 | long pi = producerIndex; 41 | 42 | if (a == null) 43 | { 44 | a = new T[8]; 45 | m = 7; 46 | mask = m; 47 | array = a; 48 | a[0] = value; 49 | producerIndex = 1; 50 | } 51 | else 52 | if (consumerIndex + m + 1 == pi) 53 | { 54 | int oldLen = a.Length; 55 | int offset = (int)pi & m; 56 | 57 | int newLen = oldLen << 1; 58 | m = newLen - 1; 59 | 60 | T[] b = new T[newLen]; 61 | 62 | int n = oldLen - offset; 63 | Array.Copy(a, offset, b, offset, n); 64 | Array.Copy(a, 0, b, oldLen, offset); 65 | 66 | mask = m; 67 | a = b; 68 | array = b; 69 | b[(int)pi & m] = value; 70 | producerIndex = pi + 1; 71 | } 72 | else 73 | { 74 | int offset = (int)pi & m; 75 | a[offset] = value; 76 | producerIndex = pi + 1; 77 | } 78 | return true; 79 | } 80 | 81 | public bool Poll(out T value) 82 | { 83 | long ci = consumerIndex; 84 | if (ci != producerIndex) 85 | { 86 | int offset = (int)ci & mask; 87 | value = array[offset]; 88 | 89 | array[offset] = default(T); 90 | consumerIndex = ci + 1; 91 | return true; 92 | } 93 | value = default(T); 94 | return false; 95 | } 96 | 97 | public void Drop() 98 | { 99 | long ci = consumerIndex; 100 | if (ci != producerIndex) 101 | { 102 | int offset = (int)ci & mask; 103 | 104 | array[offset] = default(T); 105 | consumerIndex = ci + 1; 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Reactor.Core/util/FalseSharing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | using System.Runtime.InteropServices; 15 | 16 | namespace Reactor.Core.util 17 | { 18 | /// 19 | /// A pad of 56 bytes, useful in combination with a 8 byte data field. 20 | /// 21 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 22 | internal struct Pad56 23 | { 24 | long p00, p01, p02, p03, p04, p05, p06; 25 | } 26 | 27 | /// 28 | /// A pad of 64 bytes. 29 | /// 30 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 31 | internal struct Pad64 32 | { 33 | long p00, p01, p02, p03, p04, p05, p06, p07; 34 | } 35 | 36 | /// 37 | /// A pad of 120 bytes, useful in combination with a 8 byte data field. 38 | /// 39 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 40 | internal struct Pad120 41 | { 42 | long p00, p01, p02, p03, p04, p05, p06; 43 | long p08, p09, p10, p11, p12, p13, p14, p15; 44 | } 45 | 46 | /// 47 | /// A pad of 112 bytes, useful in combination with a 16 byte data field. 48 | /// 49 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 50 | internal struct Pad112 51 | { 52 | long p00, p01, p02, p03, p04, p05; 53 | long p08, p09, p10, p11, p12, p13, p14, p15; 54 | } 55 | 56 | /// 57 | /// A pad of 14 bytes, useful in combination with a 24 byte data field. 58 | /// 59 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 60 | internal struct Pad104 61 | { 62 | long p00, p01, p02, p03, p04; 63 | long p08, p09, p10, p11, p12, p13, p14, p15; 64 | } 65 | 66 | /// 67 | /// A pad of 128 bytes. 68 | /// 69 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 70 | internal struct Pad128 71 | { 72 | long p00, p01, p02, p03, p04, p05, p06, p07; 73 | long p08, p09, p10, p11, p12, p13, p14, p15; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Reactor.Core/util/IndexedMultipleDisposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.util 15 | { 16 | /// 17 | /// Tracks IDisposables with an associated index and replaces them 18 | /// only if an incoming index is bigger than the hosted index. 19 | /// 20 | internal struct IndexedMultipeDisposableStruct 21 | { 22 | IndexedEntry entry; 23 | 24 | public bool Replace(IDisposable next, long nextIndex) 25 | { 26 | var e = Volatile.Read(ref entry); 27 | for (;;) 28 | { 29 | if (e == IndexedEntry.DISPOSED) 30 | { 31 | next?.Dispose(); 32 | return false; 33 | } 34 | if (e != null) 35 | { 36 | if (e.index > nextIndex) 37 | { 38 | return true; 39 | } 40 | } 41 | IndexedEntry u = new IndexedEntry(nextIndex, next); 42 | 43 | IndexedEntry v = Interlocked.CompareExchange(ref entry, u, e); 44 | if (v == e) 45 | { 46 | return true; 47 | } 48 | else 49 | { 50 | e = v; 51 | } 52 | } 53 | } 54 | 55 | public void Dispose() 56 | { 57 | var a = Volatile.Read(ref entry); 58 | if (a != IndexedEntry.DISPOSED) 59 | { 60 | a = Interlocked.Exchange(ref entry, IndexedEntry.DISPOSED); 61 | if (a != IndexedEntry.DISPOSED) 62 | { 63 | a?.d?.Dispose(); 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | /// 71 | /// Tracks IDisposables with an associated index and replaces them 72 | /// only if an incoming index is bigger than the hosted index. 73 | /// 74 | internal sealed class IndexedMultipleDisposable : IDisposable 75 | { 76 | IndexedMultipeDisposableStruct entry; 77 | 78 | public bool Replace(IDisposable next, long nextIndex) 79 | { 80 | return entry.Replace(next, nextIndex); 81 | } 82 | 83 | public void Dispose() 84 | { 85 | entry.Dispose(); 86 | } 87 | } 88 | 89 | sealed class IndexedEntry 90 | { 91 | 92 | internal static readonly IndexedEntry DISPOSED = new IndexedEntry(long.MaxValue, null); 93 | 94 | internal readonly long index; 95 | 96 | internal readonly IDisposable d; 97 | 98 | internal IndexedEntry(long index, IDisposable d) 99 | { 100 | this.index = index; 101 | this.d = d; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Reactor.Core/util/MultiSourceHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.util 16 | { 17 | /// 18 | /// Utility methods for dealing with values in an array or IEnumerable and 19 | /// converting them into an array. 20 | /// 21 | internal static class MultiSourceHelper 22 | { 23 | public static T[] AppendFirst(T[] array, T value) 24 | { 25 | int n = array.Length; 26 | var a = new T[n + 1]; 27 | Array.Copy(array, 0, a, 1, n); 28 | a[0] = value; 29 | return a; 30 | } 31 | 32 | public static T[] AppendLast(T[] array, T value) 33 | { 34 | int n = array.Length; 35 | var a = new T[n + 1]; 36 | Array.Copy(array, 0, a, 0, n); 37 | a[n] = value; 38 | return a; 39 | } 40 | 41 | public static bool ToArray(T[] values, IEnumerable valuesEnumerable, ISubscriber s, out int n, out T[] array) 42 | { 43 | if (values != null) 44 | { 45 | array = values; 46 | n = values.Length; 47 | } 48 | else 49 | { 50 | var i = 0; 51 | var a = new T[8]; 52 | 53 | try 54 | { 55 | foreach (var e in valuesEnumerable) 56 | { 57 | if (i == a.Length) 58 | { 59 | var b = new T[i + (i >> 1)]; 60 | Array.Copy(a, 0, b, 0, i); 61 | a = b; 62 | } 63 | a[i] = e; 64 | 65 | i++; 66 | } 67 | } 68 | catch (Exception ex) 69 | { 70 | ExceptionHelper.ThrowIfFatal(ex); 71 | EmptySubscription.Error(s, ex); 72 | array = null; 73 | n = 0; 74 | return false; 75 | } 76 | 77 | array = a; 78 | n = i; 79 | } 80 | 81 | return true; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Reactor.Core/util/MultipleDisposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.util 15 | { 16 | /// 17 | /// An IDisposable holding onto another IDisposable and allows 18 | /// replacing it atomically, optionally disposing the previous one. 19 | /// 20 | internal sealed class MultipleDisposable : IDisposable 21 | { 22 | IDisposable d; 23 | 24 | internal MultipleDisposable() 25 | { 26 | } 27 | 28 | internal MultipleDisposable(IDisposable d) 29 | { 30 | this.d = d; 31 | } 32 | 33 | public void Dispose() 34 | { 35 | DisposableHelper.Dispose(ref d); 36 | } 37 | 38 | public bool Replace(IDisposable next) 39 | { 40 | return DisposableHelper.Replace(ref d, next); 41 | } 42 | 43 | public bool Set(IDisposable next) 44 | { 45 | return DisposableHelper.Set(ref d, next); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Reactor.Core/util/ObjectHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.util 16 | { 17 | /// 18 | /// Object-helper methods. 19 | /// 20 | internal static class ObjectHelper 21 | { 22 | /// 23 | /// Throws an Exception if the value is null, returns it otherwise. 24 | /// 25 | /// The value type. 26 | /// The value. 27 | /// The error message. 28 | /// The value. 29 | internal static T RequireNonNull(T value, string errorMessage) where T : class 30 | { 31 | if (value == null) 32 | { 33 | throw new NullReferenceException(errorMessage); 34 | } 35 | return value; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Reactor.Core/util/OrderedItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.util 16 | { 17 | /// 18 | /// Basic implementation of IOrderedItem. 19 | /// 20 | /// 21 | internal sealed class OrderedItem : IOrderedItem 22 | { 23 | readonly long index; 24 | 25 | readonly T value; 26 | 27 | /// 28 | public long Index 29 | { 30 | get 31 | { 32 | return index; 33 | } 34 | } 35 | 36 | /// 37 | public T Value 38 | { 39 | get 40 | { 41 | return value; 42 | } 43 | } 44 | 45 | /// 46 | /// Constructs an ordered item with the given index and value. 47 | /// 48 | /// The index. 49 | /// The value. 50 | public OrderedItem(long index, T value) 51 | { 52 | this.index = index; 53 | this.value = value; 54 | } 55 | 56 | /// 57 | public int CompareTo(IOrderedItem other) 58 | { 59 | return index < other.Index ? -1 : (index > other.Index ? 1 : 0); 60 | } 61 | 62 | /// 63 | public IOrderedItem Replace(R value) 64 | { 65 | return new OrderedItem(index, value); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Reactor.Core/util/QueueDrainHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscription; 12 | using Reactor.Core.util; 13 | 14 | namespace Reactor.Core.util 15 | { 16 | /// 17 | /// Helper methods to work with the regular queue-drain serialization approach 18 | /// 19 | public static class QueueDrainHelper 20 | { 21 | /// 22 | /// Atomically increment the work-in-progress counter and return true if 23 | /// it transitioned from 0 to 1. 24 | /// 25 | /// The work-in-progress field 26 | /// True if the counter transitioned from 0 to 1 27 | public static bool Enter(ref int wip) 28 | { 29 | return Interlocked.Increment(ref wip) == 1; 30 | } 31 | 32 | /// 33 | /// Atomically try to decrement the work-in-progress counter and return 34 | /// its new value. 35 | /// 36 | /// The target work-in-progress counter field 37 | /// The number to decrement the counter, positive (not verified) 38 | /// The new work-in-progress value 39 | public static int Leave(ref int wip, int missed) 40 | { 41 | int w = Volatile.Read(ref wip); 42 | if (w == missed) 43 | { 44 | return Interlocked.Add(ref wip, -missed); 45 | } 46 | else 47 | { 48 | return w; 49 | } 50 | } 51 | 52 | /// 53 | /// Constructs a queue based on the prefetch value. 54 | /// 55 | /// The queue element type 56 | /// If negative, an SpscLinkedArrayQueue is created with 57 | /// capacity hint as the absolute of capacityHint, 58 | /// if one, an SpscOneQueue is created. Otherwise, an SpscArrayQueue is created with 59 | /// the capacityHint. 60 | /// 61 | public static IQueue CreateQueue(int capacityHint) 62 | { 63 | if (capacityHint < 0) 64 | { 65 | return new SpscLinkedArrayQueue(-capacityHint); 66 | } 67 | else 68 | if (capacityHint == 1) 69 | { 70 | return new SpscOneQueue(); 71 | } 72 | return new SpscArrayQueue(capacityHint); 73 | } 74 | 75 | /// 76 | /// Tries to enter the drain mode via a fast-path method. 77 | /// 78 | /// The work-in-progress field to change 79 | /// True if successful 80 | public static bool TryEnter(ref int wip) 81 | { 82 | return Volatile.Read(ref wip) == 0 && Interlocked.CompareExchange(ref wip, 1, 0) == 0; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Reactor.Core/util/QueueHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.util 16 | { 17 | /// 18 | /// Utility methods to work with IQueues. 19 | /// 20 | internal static class QueueHelper 21 | { 22 | /// 23 | /// Rounds the value to a power-of-2 if not already power of 2 24 | /// 25 | /// The value to round 26 | /// The rounded value. 27 | internal static int Round(int v) 28 | { 29 | v--; 30 | v |= v >> 1; 31 | v |= v >> 2; 32 | v |= v >> 4; 33 | v |= v >> 8; 34 | v |= v >> 16; 35 | return v + 1; 36 | } 37 | 38 | /// 39 | /// Clear the queue by polling until no more items left. 40 | /// 41 | /// The value type. 42 | /// The source queue. 43 | internal static void Clear(IQueue q) 44 | { 45 | T dummy; 46 | 47 | while (q.Poll(out dummy) && !q.IsEmpty()) ; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Reactor.Core/util/SpscOneQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Reactive.Streams; 8 | using Reactor.Core; 9 | using System.Threading; 10 | using Reactor.Core.flow; 11 | using Reactor.Core.subscriber; 12 | using Reactor.Core.subscription; 13 | using Reactor.Core.util; 14 | 15 | namespace Reactor.Core.util 16 | { 17 | /// 18 | /// A queue with capacity of one. 19 | /// 20 | /// The value type. 21 | public sealed class SpscOneQueue : IQueue 22 | { 23 | bool hasValue; 24 | T value; 25 | 26 | /// 27 | public void Clear() 28 | { 29 | value = default(T); 30 | Volatile.Write(ref hasValue, false); 31 | } 32 | 33 | /// 34 | public bool IsEmpty() 35 | { 36 | return !Volatile.Read(ref hasValue); 37 | } 38 | 39 | /// 40 | public bool Offer(T value) 41 | { 42 | if (Volatile.Read(ref hasValue)) 43 | { 44 | return false; 45 | } 46 | this.value = value; 47 | Volatile.Write(ref hasValue, true); 48 | return true; 49 | } 50 | 51 | /// 52 | public bool Poll(out T value) 53 | { 54 | if (Volatile.Read(ref hasValue)) 55 | { 56 | value = this.value; 57 | this.value = default(T); 58 | Volatile.Write(ref hasValue, false); 59 | return true; 60 | } 61 | value = default(T); 62 | return false; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /reactor-core-dotnet.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Core", "Reactor.Core\Reactor.Core.csproj", "{575C82D9-2A77-4BBF-AA31-A52B0EE8B32A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Core.Test", "Reactor.Core.Test\Reactor.Core.Test.csproj", "{325EE400-42DF-4EF5-BA5C-6667CB9D3BBD}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {575C82D9-2A77-4BBF-AA31-A52B0EE8B32A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {575C82D9-2A77-4BBF-AA31-A52B0EE8B32A}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {575C82D9-2A77-4BBF-AA31-A52B0EE8B32A}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {575C82D9-2A77-4BBF-AA31-A52B0EE8B32A}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {325EE400-42DF-4EF5-BA5C-6667CB9D3BBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {325EE400-42DF-4EF5-BA5C-6667CB9D3BBD}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {325EE400-42DF-4EF5-BA5C-6667CB9D3BBD}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {325EE400-42DF-4EF5-BA5C-6667CB9D3BBD}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | --------------------------------------------------------------------------------