Skip to content

Comments

Add ReactiveUI.Extensions Async module#117

Open
ChrisPulman wants to merge 12 commits intomainfrom
AddNewExtensions
Open

Add ReactiveUI.Extensions Async module#117
ChrisPulman wants to merge 12 commits intomainfrom
AddNewExtensions

Conversation

@ChrisPulman
Copy link
Member

What kind of change does this PR introduce?

Update / Feature

What is the new behavior?

Introduce a new Async module for ReactiveUI.Extensions: adds comprehensive async support including AsyncContext, observables, observers, connectable observables, a wide set of operators, subjects, internals (gates, cancellable subscriptions, anonymous types), and async disposables (Composite, Serial, SingleAssignment, helpers).

Also update Directory.Packages.props (bump Microsoft.SourceLink.GitHub and add several System/Microsoft packages) and adjust the ReactiveUI.Extensions project file to include the new sources.
This commit scaffolds full asynchronous reactive primitives and utilities used across the extension library.

Introduce a full Async Observable implementation and comprehensive test suite.

Adds core async types and bridge code (IObservableAsync, IObserverAsync, ObservableAsync, ObserverAsync, ObservableBridgeExtensions, AsyncContext), many operator implementations (Merge, Concat, CombineLatest, Zip, SelectMany, Delay, Retry, Throttle, Timeout, StartWith, TakeWhile, SkipWhile, etc.), subject variants and internals (multicast, wrapped observers, cancellable subscriptions), and subject mixins.

Also adds numerous NUnit test files under src/ReactiveUI.Extensions.Tests/Async (AdditionalOperatorTests, BridgeTests, CombiningOperatorTests, CoverageBoostTests, DeepCoverageTests, DisposableTests, ErrorHandlingOperatorTests, FactoryObservableTests, FilteringOperatorTests, ResultAndInfrastructureTests, SubjectTests, TerminalOperatorTests, TimeBasedOperatorTests, TransformationOperatorTests, AsyncTestHelpers) and updates project/test wiring.

These changes enable bridging with System.Reactive, expand operator coverage, and improve test coverage across many edge cases.

Clean up and refactor various async operator and subject implementations: remove unused usings and redundant comments, replace explicit local types with var for consistency, simplify a method to an expression-bodied form, and use IsEmpty for buffer checks.

Add XML documentation for ConcatEnumerableObservable and ZipObservable to clarify behavior and type parameters. These changes improve readability, reduce compiler/editor warnings, and clarify intent without altering behavior.

Add a comprehensive "Async Observables (IObservableAsync)" section to the README covering design goals, quick start, API catalogue, core interfaces/types, factory methods, operators (transformation, filtering, combining, timing, aggregation, error handling), subjects, bridging/conversion, async disposables, examples and usage notes.

Also update Performance Notes and Thread Safety with async-specific guidance, add a changelog line announcing the async-native framework, fix a small typography change (allocation‑aware hyphen), and correct a few code snippet var/formatting issues.

What might this PR break?

Minor changes to existing code.
Added support for ValueTask, IObservableAsync, IObserverAsync and IAsyncDisposable

Please check if the PR fulfills these requirements

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

Other information:

Introduce a new Async module for ReactiveUI.Extensions: adds comprehensive async support including AsyncContext, observables, observers, connectable observables, a wide set of operators, subjects, internals (gates, cancelable subscriptions, anonymous types), and async disposables (Composite, Serial, SingleAssignment, helpers).

Also update Directory.Packages.props (bump Microsoft.SourceLink.GitHub and add several System/Microsoft packages) and adjust the ReactiveUI.Extensions project file to include the new sources. This commit scaffolds full asynchronous reactive primitives and utilities used across the extension library.
Introduce a full Async Observable implementation and comprehensive test suite. Adds core async types and bridge code (IObservableAsync, IObserverAsync, ObservableAsync, ObserverAsync, ObservableBridgeExtensions, AsyncContext), many operator implementations (Merge, Concat, CombineLatest, Zip, SelectMany, Delay, Retry, Throttle, Timeout, StartWith, TakeWhile, SkipWhile, etc.), subject variants and internals (multicast, wrapped observers, cancelable subscriptions), and subject mixins. Also adds numerous NUnit test files under src/ReactiveUI.Extensions.Tests/Async (AdditionalOperatorTests, BridgeTests, CombiningOperatorTests, CoverageBoostTests, DeepCoverageTests, DisposableTests, ErrorHandlingOperatorTests, FactoryObservableTests, FilteringOperatorTests, ResultAndInfrastructureTests, SubjectTests, TerminalOperatorTests, TimeBasedOperatorTests, TransformationOperatorTests, AsyncTestHelpers) and updates project/test wiring. These changes enable bridging with System.Reactive, expand operator coverage, and improve test coverage across many edge cases.
Clean up and refactor various async operator and subject implementations: remove unused usings and redundant comments, replace explicit local types with var for consistency, simplify a method to an expression-bodied form, and use IsEmpty for buffer checks. Add XML documentation for ConcatEnumerableObservable and ZipObservable to clarify behavior and type parameters. These changes improve readability, reduce compiler/editor warnings, and clarify intent without altering behavior.
Add a comprehensive "Async Observables (IObservableAsync<T>)" section to the README covering design goals, quick start, API catalog, core interfaces/types, factory methods, operators (transformation, filtering, combining, timing, aggregation, error handling), subjects, bridging/conversion, async disposables, examples and usage notes. Also update Performance Notes and Thread Safety with async-specific guidance, add a changelog line announcing the async-native framework, fix a small typography change (allocation‑aware hyphen), and correct a few code snippet var/formatting issues.
Introduce a new DebounceUntil<T>(..., TimeSpan, Func<T,bool>, IScheduler) overload that uses the supplied scheduler for Delay, enabling deterministic scheduling in tests. Update the DebounceUntil unit test to use TestScheduler, pass it into the operator, replace Thread.Sleep with scheduler.AdvanceBy, and adjust timing to use FromTicks so the test runs deterministically.
In StartAsync, add a sentinel Interlocked.Increment(ref _active) before subscribing to sources and replace the Volatile.Read check with Interlocked.Decrement(ref _active) after the loop. This prevents a synchronously-completing inner source from driving _active to zero before subsequent sources are subscribed, avoiding premature termination of the merge. Also adds explanatory comments and uses interlocked operations for correct race-free behavior.
@codecov
Copy link

codecov bot commented Feb 16, 2026

Codecov Report

❌ Patch coverage is 74.72186% with 977 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.60%. Comparing base (d3bb06e) to head (595e026).

Files with missing lines Patch % Lines
...tiveUI.Extensions/Async/Operators/CombineLatest.cs 74.35% 94 Missing and 143 partials ⚠️
...ReactiveUI.Extensions/Async/Operators/TakeUntil.cs 55.29% 130 Missing and 5 partials ⚠️
src/ReactiveUI.Extensions/Async/Operators/Merge.cs 72.86% 48 Missing and 6 partials ⚠️
...eUI.Extensions/Async/Operators/SwitchObservable.cs 68.00% 30 Missing and 2 partials ⚠️
...ensions/Async/Bridge/ObservableBridgeExtensions.cs 70.75% 27 Missing and 4 partials ⚠️
src/ReactiveUI.Extensions/Async/Operators/Zip.cs 62.82% 17 Missing and 12 partials ⚠️
src/ReactiveUI.Extensions/Async/AsyncContext.cs 50.94% 23 Missing and 3 partials ⚠️
src/ReactiveUI.Extensions/Async/ObserverAsync.cs 71.91% 22 Missing and 3 partials ⚠️
...iveUI.Extensions/Async/Operators/SubscribeAsync.cs 38.46% 19 Missing and 5 partials ⚠️
...sync/Subjects/Base/BaseReplayLatestSubjectAsync.cs 58.92% 20 Missing and 3 partials ⚠️
... and 67 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #117      +/-   ##
==========================================
- Coverage   74.84%   74.60%   -0.24%     
==========================================
  Files           8      117     +109     
  Lines         791     4742    +3951     
  Branches       83      643     +560     
==========================================
+ Hits          592     3538    +2946     
- Misses        173      907     +734     
- Partials       26      297     +271     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Add new test file src/ReactiveUI.Extensions.Tests/Async/CombineLatestOperatorTests.cs containing comprehensive NUnit tests for the CombineLatest async operator. Covers arities 2–8 and verifies behavior for emissions (no emission until all sources have values, latest-value combinings), error propagation and completion semantics, error-resume forwarding, disposal handling (including double-dispose and ignoring resumes after dispose), and several cross-cutting edge cases.
Restructure and expand .editorconfig with detailed code-style, analyzer and naming rules. Add CI/config files (codecov.yml, global.json, testconfig.json) and replace the old .sln with a .slnx. Remove a parallel AssemblyInfo and apply widespread updates to the Async implementation and corresponding tests (subjects, operators, disposables, internals, and test project files) to align with the new style and analyzer expectations.
Add AsyncTestHelpers.WaitForConditionAsync to provide polling-based waits with timeouts, and replace Thread.Sleep/manual polling in tests with this helper. Updated TimeBasedOperatorTests and ReactiveExtensionsTests to await conditions (and assert the wait succeeded) for more reliable, deterministic timing in async tests, and added the necessary using directive in ReactiveExtensionsTests.
Increase timeouts and make async test waits more robust to reduce flakiness. Updated TimeBasedOperatorTests and ReactiveExtensionsTests to use a 5s WaitForConditionAsync instead of shorter delays, replaced a Task.Delay with WaitForConditionAsync that checks both result and exception, and strengthened a retry test to wait for the expected error count before asserting.
Extend flaky test waits and make completion assertions more robust. Increased TimeBasedOperatorTests wait timeouts from 2s to 5s to reduce timing-related failures. In ReactiveExtensionsTests replaced a simple Task.WaitAsync with WaitForConditionAsync that verifies both completion flag and result count, and added an assertion for the condition result. These changes aim to stabilize CI/test runs by allowing more time and using a deterministic completion check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant