Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
461 changes: 256 additions & 205 deletions .editorconfig

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<!-- StyleSharp.Analyzers, PerformanceSharp.Analyzers and SecuritySharp.Analyzers ship from the
same release pipeline and always share a version. -->
<RoslynCommonAnalyzersVersion>3.33.0</RoslynCommonAnalyzersVersion>
<RoslynCommonAnalyzersVersion>3.38.1</RoslynCommonAnalyzersVersion>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.301"/>
Expand All @@ -18,7 +18,7 @@
<PackageVersion Include="Roslynator.Analyzers" Version="4.15.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="5.6.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="5.6.0"/>
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.29.0.143774"/>
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.30.0.144632"/>
</ItemGroup>
<!-- Benchmarks + tests -->
<ItemGroup>
Expand All @@ -45,7 +45,7 @@
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="11.0.0-preview.6.26359.118" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.Extensions.Logging" Version="11.0.0-preview.6.26359.118" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="11.0.0-preview.6.26359.118" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.Maui.Core" Version="10.0.80" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0')) AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.Maui.Core" Version="10.0.90" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0')) AND !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.Maui.Core" Version="11.0.0-preview.6.26360.8" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))"/>
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="2.3.1"/>
</ItemGroup>
Expand All @@ -65,7 +65,7 @@
<ItemGroup>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0"/>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1"/>
<PackageVersion Include="TUnit" Version="1.61.23"/>
<PackageVersion Include="TUnit" Version="1.61.38"/>
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.9.0"/>
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)/directory.packages.support.props" Condition="Exists('$(MSBuildThisFileDirectory)/directory.packages.support.props')"/>
Expand Down
8 changes: 4 additions & 4 deletions src/Polyfills/RequiredMemberAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ namespace System.Runtime.CompilerServices;
[ExcludeFromCodeCoverage]
[DebuggerNonUserCode]
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Field |
AttributeTargets.Property,
AttributeTargets.Class
| AttributeTargets.Struct
| AttributeTargets.Field
| AttributeTargets.Property,
AllowMultiple = false,
Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute;
Expand Down
6 changes: 3 additions & 3 deletions src/Primitives.Async.Shared/AsyncContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ private AsyncContext()
public ISequencer? Sequencer { get; init; }

/// <summary>Gets a value indicating whether the current context uses the default task scheduler and no synchronization context.</summary>
internal bool UsesDefaultSequencer => SynchronizationContext is null &&
Sequencer is null &&
(TaskScheduler is null || TaskScheduler == TaskScheduler.Default);
internal bool UsesDefaultSequencer => SynchronizationContext is null
&& Sequencer is null
&& (TaskScheduler is null || TaskScheduler == TaskScheduler.Default);

/// <summary>Creates a new AsyncContext that uses the specified SynchronizationContext for asynchronous operations.</summary>
/// <remarks>The returned AsyncContext will have its TaskScheduler property set to null. Use this method
Expand Down
4 changes: 2 additions & 2 deletions src/Primitives.Async.Shared/Mixins/AsyncContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public bool IsSameAsCurrentAsyncContext()

if (@this.Sequencer is not null)
{
return TaskScheduler.Current is AsyncContext.SequencerTaskScheduler adapter &&
ReferenceEquals(adapter.Sequencer, @this.Sequencer);
return TaskScheduler.Current is AsyncContext.SequencerTaskScheduler adapter
&& ReferenceEquals(adapter.Sequencer, @this.Sequencer);
}

return @this.TaskScheduler is not null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ async ValueTask<IAsyncDisposable> IObservableAsync<RxVoid>.SubscribeAsync(
/// <summary>Forwards <see cref = "RxVoid.Default"/> for every upstream emission.</summary>
/// <param name = "downstream">The downstream observer.</param>
/// <param name = "subscribeToken">The subscribe-time cancellation token.</param>
internal sealed class AsSignalWitness(IObserverAsync<RxVoid> downstream, CancellationToken subscribeToken)
: WitnessAsync<T>(subscribeToken)
internal sealed class AsSignalWitness(IObserverAsync<RxVoid> downstream, CancellationToken subscribeToken) : WitnessAsync<T>(subscribeToken)
{
/// <inheritdoc/>
protected override ValueTask OnNextAsyncCore(T value, CancellationToken cancellationToken) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public void OnError(Exception error)

if (_retries < policy.MaxRetries)
{
var delay = TimeSpan.FromTicks((long)(policy.InitialDelay.Ticks *
Math.Pow(policy.BackoffFactor, _retries)));
var delay = TimeSpan.FromTicks((long)(policy.InitialDelay.Ticks
* Math.Pow(policy.BackoffFactor, _retries)));
if (policy.MaxDelay.HasValue && delay > policy.MaxDelay.Value)
{
delay = policy.MaxDelay.Value;
Expand Down
4 changes: 2 additions & 2 deletions src/Primitives.Extensions.Shared/ReactiveExtensions.Retry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ public IObservable<T> RetryForeverWithDelay(TimeSpan delay) =>
/// <param name="retryCount">The retry count.</param>
/// <param name="delay">The delay.</param>
/// <returns>An IObservable of T.</returns>
public IObservable<T> RetryWithFixedDelay(int retryCount, TimeSpan delay)
=> new RetryWithBackoffObservable<T>(
public IObservable<T> RetryWithFixedDelay(int retryCount, TimeSpan delay) =>
new RetryWithBackoffObservable<T>(
source,
new(
retryCount,
Expand Down
4 changes: 2 additions & 2 deletions src/Primitives.Shared/Advanced/ExpireSignal{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public ExpireSignal(IObservable<T> source, TimeSpan dueTime, ISequencer sequence

/// <inheritdoc/>
public bool IsRequiredSubscribeOnCurrentThread() =>
_sequencer == Sequencer.CurrentThread ||
(_source is IRequireCurrentThread<T> currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());
_sequencer == Sequencer.CurrentThread
|| (_source is IRequireCurrentThread<T> currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());

/// <inheritdoc/>
public IDisposable Subscribe(IObserver<T> observer)
Expand Down
4 changes: 2 additions & 2 deletions src/Primitives.Shared/Advanced/FromAsyncTaskObservation{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ private void OnSuccess(T value)
/// <param name="error">The observed task error.</param>
private void OnError(Exception error)
{
if (Lifetime.IsCancellationRequested || ExternalCancellation.TryForwardCancellation() ||
!Lifetime.TryComplete())
if (Lifetime.IsCancellationRequested || ExternalCancellation.TryForwardCancellation()
|| !Lifetime.TryComplete())
{
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Primitives.Shared/Advanced/OnErrorResumeNextSignal{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ private void ReadNextSource(out IObservable<T>? source, out Exception? error, ou
return;
}

source = enumerator.Current ??
throw new InvalidOperationException("OnErrorResumeNext source contained null.");
source = enumerator.Current
?? throw new InvalidOperationException("OnErrorResumeNext source contained null.");
}
catch (Exception exception)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ public IDisposable Subscribe(IObserver<TOut> observer)
/// <summary>Applies the chooser to each value and forwards only the chosen ones.</summary>
/// <param name="downstream">The downstream observer that receives the chosen values.</param>
/// <param name="chooser">Maps a source value to <c>(HasValue, Value)</c>; the value is skipped when <c>HasValue</c> is <see langword="false"/>.</param>
private sealed class Sink(IObserver<TOut> downstream, Func<TIn, (bool HasValue, TOut Value)> chooser)
: IObserver<TIn>
private sealed class Sink(IObserver<TOut> downstream, Func<TIn, (bool HasValue, TOut Value)> chooser) : IObserver<TIn>
{
/// <inheritdoc/>
public void OnNext(TIn value)
Expand Down Expand Up @@ -134,8 +133,7 @@ public IDisposable Subscribe(IObserver<TResult> observer)
/// <summary>Subscribes to the source, switching the active inner subscription on each non-null value.</summary>
/// <param name="selector">Projects each non-null source value to an inner observable.</param>
/// <param name="downstream">The downstream observer that receives values from the latest inner observable.</param>
private sealed class Sink(Func<TSource, IObservable<TResult>> selector, IObserver<TResult> downstream)
: IObserver<TSource?>, IDisposable
private sealed class Sink(Func<TSource, IObservable<TResult>> selector, IObserver<TResult> downstream) : IObserver<TSource?>, IDisposable
{
/// <summary>Guards the switching state so outer and inner notifications stay consistent.</summary>
private readonly Lock _gate = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,8 +526,8 @@ private sealed class AbsoluteExpireSignal<T>(IObservable<T> source, DateTimeOffs

/// <inheritdoc/>
public bool IsRequiredSubscribeOnCurrentThread() =>
_scheduler == Sequencer.CurrentThread ||
(_source is IRequireCurrentThread<T> currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());
_scheduler == Sequencer.CurrentThread
|| (_source is IRequireCurrentThread<T> currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());

/// <inheritdoc/>
public IDisposable Subscribe(IObserver<T> observer)
Expand Down
11 changes: 4 additions & 7 deletions src/Primitives.Shared/SignalOperatorMixins.StatefulSignals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,20 +317,17 @@ public IDisposable Subscribe(IObserver<T> observer)

/// <summary>Creates the duplicate-tracking set, pre-sized when the source has a known element count.</summary>
/// <returns>The set used to track already-observed values.</returns>
private HashSet<T> CreateSeen()
{
private HashSet<T> CreateSeen() =>
#if NET8_0_OR_GREATER
var capacity = _source is RangeSignal range ? range.Count : 0;
return capacity switch
(_source is RangeSignal range ? range.Count : 0) switch
{
> 0 => new(capacity, _comparer),
var capacity when capacity > 0 => new(capacity, _comparer),
_ when _comparer is null => [],
_ => new(_comparer),
};
#else
return new(_comparer);
new(_comparer);
#endif
}
}

/// <summary>Dedicated signal for <c>Unique</c> (adjacent distinct).</summary>
Expand Down
24 changes: 12 additions & 12 deletions src/Primitives.Shared/SignalOperatorMixins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,10 @@ public IObservable<TResult> Pair<TRight, TResult>(IObservable<TRight> right, Fun

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(T) == typeof(int) &&
typeof(TRight) == typeof(int) &&
source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int)
&& typeof(TRight) == typeof(int)
&& source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeZipSignal<TResult>(
leftRange,
rightRange,
Expand All @@ -417,10 +417,10 @@ public IObservable<TResult> SyncLatest<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(T) == typeof(int) &&
typeof(TRight) == typeof(int) &&
source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int)
&& typeof(TRight) == typeof(int)
&& source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeSyncLatestSignal<TResult>(
leftRange,
rightRange,
Expand All @@ -444,10 +444,10 @@ public IObservable<TResult> Latch<TRight, TResult>(IObservable<TRight> right, Fu

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(T) == typeof(int) &&
typeof(TRight) == typeof(int) &&
source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int)
&& typeof(TRight) == typeof(int)
&& source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeWithLatestSignal<TResult>(
leftRange,
rightRange,
Expand Down
12 changes: 6 additions & 6 deletions src/Primitives.Shared/SignalOperatorParityMixins.RxNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,8 @@ public IObservable<TResult> Zip<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeZipSignal<TResult>(leftRange, rightRange, (Func<int, int, TResult>)(object)selector)
: new ZipSignal<TLeft, TRight, TResult>(left, right, selector);
}
Expand All @@ -661,8 +661,8 @@ public IObservable<TResult> CombineLatest<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeCombineLatestSignal<TResult>(
leftRange,
rightRange,
Expand All @@ -687,8 +687,8 @@ public IObservable<TResult> WithLatestFrom<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(TLeft) == typeof(int) && typeof(TRight) == typeof(int) && left is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeWithLatestSignal<TResult>(leftRange, rightRange, (Func<int, int, TResult>)(object)selector)
: new LatchSignal<TLeft, TRight, TResult>(left, right, selector);
}
Expand Down
12 changes: 6 additions & 6 deletions src/Primitives.Shared/SignalOperatorParityMixins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,8 @@ public IObservable<TResult> PairLatest<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeSyncLatestSignal<TResult>(leftRange, rightRange, (Func<int, int, TResult>)(object)selector)
: new CombineLatestSignal<T, TRight, TResult>(source, right, selector);
}
Expand All @@ -731,8 +731,8 @@ public IObservable<TResult> FuseLatest<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(source);

return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeSyncLatestSignal<TResult>(leftRange, rightRange, (Func<int, int, TResult>)(object)selector)
: new CombineLatestSignal<T, TRight, TResult>(source, right, selector);
}
Expand All @@ -754,8 +754,8 @@ public IObservable<TResult> ForkJoin<TRight, TResult>(

ArgumentExceptionHelper.ThrowIfNull(selector);

return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange &&
right is RangeSignal rightRange
return typeof(T) == typeof(int) && typeof(TRight) == typeof(int) && source is RangeSignal leftRange
&& right is RangeSignal rightRange
? new RangeForkJoinSignal<TResult>(leftRange, rightRange, (Func<int, int, TResult>)(object)selector)
: new ForkJoinSignal<T, TRight, TResult>(source, right, selector);
}
Expand Down
7 changes: 3 additions & 4 deletions src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,9 @@ public async Task HandleCancellation(Action? action)
internal async Task<(TResult Value, bool IsCanceled)> WhenCancelled(CancellationToken cancellationToken)
{
TaskCompletionSource<TResult> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
var registration = cancellationToken.Register(
static state => ((TaskCompletionSource<TResult>)state!).TrySetCanceled(),
tcs,
false);
var registration = cancellationToken.UnsafeRegister(
static (state, token) => ((TaskCompletionSource<TResult>)state!).TrySetCanceled(token),
tcs);
var cancellationTask = tcs.Task;

try
Expand Down
Loading
Loading