Skip to content

Commit 6dab874

Browse files
authored
refactor: isolate scheduler state and condense code comments (#211)
* chore: Update benchmarks and fix tests * refactor(tests): drive scheduling tests from state, not the clock - Replace delays, polling and thread rendezvous with awaited completion sources, virtual clocks and ordered calls into internal seams. - Add seams for stepwise dispatch: WasmScheduler.QueueReady and RunReadyBatch, so enqueue, dispose and drain are explicit steps. - Assert per-item dispatch counts where a total was checked before. - Trim documentation to the contract: concise summaries, inline notes at the confusing line, and remarks only for non-obvious behaviour. - Correct exception docs to the type thrown rather than the guard helper. * chore: more churn * further work * docs: state what non-public members do, not why - Reduce internal operator and helper summaries to a single line of behaviour. - Drop allocation and deadlock rationale from field and method summaries. - Keep remarks for public contracts a caller cannot infer from the signature. * Further * further * fix(concurrency): convert durations and timestamps with integer math - Scale between ticks and monotonic timestamps without a double round trip, so a duration representable on both grids survives unchanged. - A 50-tick delay converted at a 10 MHz timestamp frequency no longer lands a tick late, which left scheduled work undue at its own due time. * docs(extensions): name what each parameter carries - Replace placeholder parameter text with the role the argument plays. - Say which window a sequencer times, and which side an observer receives. * Add further tests * Fix build issue
1 parent cb8fb40 commit 6dab874

1,049 files changed

Lines changed: 18934 additions & 20515 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CLAUDE.md‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,11 @@ dotnet test "tests/ReactiveUI.Primitives.Async.Tests/ReactiveUI.Primitives.Async
134134
--treenode-filter "/*/*/*/Async"
135135
```
136136

137-
### API Approval Notes
137+
### Public API Checks
138138

139-
- API approval baselines live under `src/tests/**/ApiApprovalTests.*.verified.txt`
140-
- New TFMs usually require corresponding new `DotNet11_0.verified.txt` files
141-
- If approval tests fail with `.received.txt` output, inspect the generated snapshot and promote it intentionally if the
142-
API change is expected
139+
- `PublicApiSharp.Analyzers` checks each package's `src//PublicAPI//PublicAPI.txt` baseline.
140+
- New target frameworks require a corresponding baseline directory.
141+
- For an intentional API change, review the affected signatures and update the corresponding framework baselines.
143142

144143
---
145144

‎src/Directory.Packages.props‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
ItemGroup>
3434
<ItemGroup>
3535
<PackageVersion Include="Avalonia" Version="$(AvaloniaVersion)"/>
36-
<PackageVersion Include="Avalonia.Headless" Version="$(AvaloniaVersion)"/>
3736
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="8.0.31" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0'))"/>
3837
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="9.0.20" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0')) AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))"/>
3938
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="10.0.12" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0')) AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>

‎src/Polyfills/ArgumentExceptionHelper.cs‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77

88
namespace ReactiveUI.Primitives.Internal;
99

10-
///
11-
/// Polyfill for ArgumentNullException.ThrowIfNull on target frameworks (net462-net481) that predate it.
12-
/// On net8.0 and later this type is not compiled; consuming projects alias the ArgumentExceptionHelper
13-
/// identifier directly to so the call sites bind to the BCL method.
14-
///
10+
/// Polyfill for ArgumentNullException.ThrowIfNull on target frameworks that predate it.
1511
[ExcludeFromCodeCoverage]
1612
internal static class ArgumentExceptionHelper
1713
{

‎src/Polyfills/ArgumentOutOfRangeExceptionHelper.cs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ internal static void ThrowIfLessThan(
7070
"Design",
7171
"SST2318:Members should not have identical bodies",
7272
Justification =
73-
"A type-specialized polyfill overload. The bounds-check body is identical to the int overload only "
74-
+ "because the guard shape is the same; the two operate on different value types (int vs TimeSpan) and "
75-
+ "cannot forward to one another. This mirrors the BCL's per-type ThrowIfLessThan overloads.")]
73+
"The int and TimeSpan overloads guard different value types and cannot forward to one another.")]
7674
internal static void ThrowIfLessThan(
7775
TimeSpan value,
7876
TimeSpan other,

‎src/Polyfills/ObjectDisposedExceptionHelper.cs‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@
66

77
namespace ReactiveUI.Primitives.Internal;
88

9-
///
10-
/// Polyfill for ObjectDisposedException.ThrowIf on target frameworks (net462-net481) that predate it.
11-
/// On net8.0 and later this type is not compiled; consuming projects alias the ObjectDisposedExceptionHelper
12-
/// identifier directly to so the call sites bind to the BCL method.
13-
///
9+
/// Polyfill for ObjectDisposedException.ThrowIf on target frameworks that predate it.
1410
[ExcludeFromCodeCoverage]
1511
internal static class ObjectDisposedExceptionHelper
1612
{

‎src/Polyfills/TaskCompletionSource.cs‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal sealed class TaskCompletionSource
1919

2020
/// Initializes a new instance of the class.
2121
[SuppressMessage("Concurrency", "PSH1302", Justification =
22-
"BCL-parity polyfill; must match the framework ctor's TaskCreationOptions.None default, not force async continuations.")]
22+
"Matches the framework constructor's TaskCreationOptions.None default.")]
2323
public TaskCompletionSource() => _inner = new();
2424

2525
/// Transitions the underlying task to the state.
@@ -47,9 +47,7 @@ internal sealed class TaskCompletionSource
4747
"Design",
4848
"SST2318:Members should not have identical bodies",
4949
Justification =
50-
"Distinct BCL-parity surface members with different contracts and return types: SetCanceled is void and "
51-
+ "TrySetCanceled returns bool. They share the same backing call here but must track the framework surface "
52-
+ "independently, so they are deliberately kept as separate members rather than one forwarding to the other.")]
50+
"SetCanceled returns void and TrySetCanceled returns bool; each tracks its own framework contract.")]
5351
internal bool TrySetCanceled() => _inner.TrySetCanceled();
5452

5553
/// Attempts to transition the underlying task to the state for the specified token.

‎src/Polyfills/TaskPolyfillExtensions.cs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private static async Task WaitForCompletionAsync(Task task, TimeSpan timeout, Ca
5858
using var linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
5959
if (timeout != Timeout.InfiniteTimeSpan)
6060
{
61-
linked.CancelAfter(timeout);
61+
ScheduleTimeout(linked, timeout);
6262
}
6363

6464
using (linked.Token.Register(static state => ((TaskCompletionSource<bool>)state).TrySetResult(true), signal))
@@ -71,5 +71,12 @@ private static async Task WaitForCompletionAsync(Task task, TimeSpan timeout, Ca
7171
}
7272
}
7373
}
74+
75+
/// Schedules cancellation when the timeout elapses.
76+
/// The cancellation source.
77+
/// The timeout duration.
78+
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
79+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
80+
private static void ScheduleTimeout(CancellationTokenSource source, TimeSpan timeout) => source.CancelAfter(timeout);
7481
}
7582
#endif

‎src/Primitives.Async.Shared/Advanced/StartSubscription.cs‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,21 @@ protected override async ValueTask ExecuteAsyncCore(
4646
return;
4747
}
4848

49-
await Task.Factory.StartNew(
49+
await ExecuteOnSchedulerAsync(observer, taskScheduler, cancellationToken).ConfigureAwait(false);
50+
}
51+
52+
/// Starts the action through the supplied scheduler.
53+
/// The observer receiving the signal notification.
54+
/// The scheduler that starts the action.
55+
/// Cancellation for the scheduled task and notifications.
56+
/// The scheduled action and notification operation.
57+
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
58+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
59+
private Task ExecuteOnSchedulerAsync(
60+
IObserverAsync<RxVoid> observer,
61+
TaskScheduler taskScheduler,
62+
CancellationToken cancellationToken) =>
63+
Task.Factory.StartNew(
5064
static s =>
5165
{
5266
var (self, observer, cancellationToken) =
@@ -57,9 +71,7 @@ await Task.Factory.StartNew(
5771
cancellationToken,
5872
TaskCreationOptions.DenyChildAttach,
5973
taskScheduler)
60-
.Unwrap()
61-
.ConfigureAwait(false);
62-
}
74+
.Unwrap();
6375

6476
/// Runs the action and forwards the completion signal.
6577
/// The observer receiving the signal notification.

0 commit comments

Comments
 (0)