From c539237f7ec97718042649b6853eede8c2e36acb Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:37:58 +0000 Subject: [PATCH 1/7] Update to release version of .NET 8 --- .github/workflows/build.yml | 2 +- Directory.Build.props | 3 --- Funcky.Async/Funcky.Async.csproj | 3 +-- Funcky/Funcky.csproj | 5 ++--- global.json | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0cc4457c..53119ae9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: - uses: actions/setup-dotnet@v3 name: Install Current .NET SDK - name: Generate NuGet Packages - run: dotnet pack --configuration Release --output nupkg /p:FunckyBuildWithPreviewTargetFramework=false + run: dotnet pack --configuration Release --output nupkg - uses: actions/upload-artifact@v3 if: success() && github.ref == 'refs/heads/main' with: diff --git a/Directory.Build.props b/Directory.Build.props index cd74e938..3b750436 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,9 +26,6 @@ - - true - $(MSBuildThisFileDirectory)artifacts diff --git a/Funcky.Async/Funcky.Async.csproj b/Funcky.Async/Funcky.Async.csproj index da8da973..ad56a00f 100644 --- a/Funcky.Async/Funcky.Async.csproj +++ b/Funcky.Async/Funcky.Async.csproj @@ -1,7 +1,6 @@ - net5.0;netstandard2.1;netstandard2.0 - net8.0;$(TargetFrameworks) + net8.0;net5.0;netstandard2.1;netstandard2.0 preview enable Extends Funcky with support for IAsyncEnumerable and Tasks. diff --git a/Funcky/Funcky.csproj b/Funcky/Funcky.csproj index e9972412..fe22961e 100644 --- a/Funcky/Funcky.csproj +++ b/Funcky/Funcky.csproj @@ -1,7 +1,6 @@ - net7.0;net6.0;net5.0;netcoreapp3.1;netstandard2.0;netstandard2.1 - net8.0;$(TargetFrameworks) + net8.0;net7.0;net6.0;net5.0;netcoreapp3.1;netstandard2.0;netstandard2.1 preview enable Funcky @@ -19,7 +18,7 @@ $(DefineConstants);CONTRACTS_FULL - net7.0 + net8.0 diff --git a/global.json b/global.json index 5d540d5e..3f809cbf 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.100-preview.5.23303.2", + "version": "8.0.100", "rollForward": "feature" } } From 523530cb622e1b4aa720a573eae07c5c360d1d64 Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:46:44 +0000 Subject: [PATCH 2/7] Suppress compatibility warning --- Funcky/CompatibilitySuppressions.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Funcky/CompatibilitySuppressions.xml diff --git a/Funcky/CompatibilitySuppressions.xml b/Funcky/CompatibilitySuppressions.xml new file mode 100644 index 00000000..96b033ac --- /dev/null +++ b/Funcky/CompatibilitySuppressions.xml @@ -0,0 +1,10 @@ + + + + + CP0002 + M:Funcky.Extensions.EnumerableExtensions.Chunk``1(System.Collections.Generic.IEnumerable{``0},System.Int32) + lib/net5.0/Funcky.dll + lib/net6.0/Funcky.dll + + \ No newline at end of file From 15c9ab7c533f0690a2b4f58f38a9f0bb8573e698 Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:50:25 +0000 Subject: [PATCH 3/7] Remove explicit `--configuration Release` Pack uses the release configuration by default now. --- .github/workflows/build.yml | 2 +- .github/workflows/publish-nightly-package.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53119ae9..1b506bc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: - uses: actions/setup-dotnet@v3 name: Install Current .NET SDK - name: Generate NuGet Packages - run: dotnet pack --configuration Release --output nupkg + run: dotnet pack --output nupkg - uses: actions/upload-artifact@v3 if: success() && github.ref == 'refs/heads/main' with: diff --git a/.github/workflows/publish-nightly-package.yml b/.github/workflows/publish-nightly-package.yml index 54de91e6..7d36db7b 100644 --- a/.github/workflows/publish-nightly-package.yml +++ b/.github/workflows/publish-nightly-package.yml @@ -13,6 +13,6 @@ jobs: - uses: actions/setup-dotnet@v3 name: Install Current .NET SDK - name: Pack Packages - run: dotnet pack Funcky/Funcky.csproj --configuration Release --output nupkg --version-suffix "nightly.$(git rev-parse --short "${{github.sha}}")" /p:GeneratePackageOnBuild=false + run: dotnet pack Funcky/Funcky.csproj --output nupkg --version-suffix "nightly.$(git rev-parse --short "${{github.sha}}")" - name: Push Package run: dotnet nuget push --source https://nuget.pkg.github.com/polyadic/index.json --api-key ${{secrets.GITHUB_TOKEN}} nupkg/Funcky.*.nupkg From f358dc0c34a7d214da2addc75f8a36843d82c4a2 Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 21:27:13 +0100 Subject: [PATCH 4/7] Only set IsTrimmable=true for compatible TFMs --- Funcky.Async/Funcky.Async.csproj | 4 +--- Funcky/Funcky.csproj | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Funcky.Async/Funcky.Async.csproj b/Funcky.Async/Funcky.Async.csproj index ad56a00f..631d1813 100644 --- a/Funcky.Async/Funcky.Async.csproj +++ b/Funcky.Async/Funcky.Async.csproj @@ -19,9 +19,7 @@ Funcky $(DefineConstants);CONTRACTS_FULL - - + true true diff --git a/Funcky/Funcky.csproj b/Funcky/Funcky.csproj index fe22961e..5dd037d6 100644 --- a/Funcky/Funcky.csproj +++ b/Funcky/Funcky.csproj @@ -38,9 +38,7 @@ - - + true true From d27733f9f1b10db61598d2ee55d0fc9f854d1c0d Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 21:40:58 +0100 Subject: [PATCH 5/7] Track new ParseOrNone overloads --- Funcky/PublicAPI.Unshipped.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Funcky/PublicAPI.Unshipped.txt b/Funcky/PublicAPI.Unshipped.txt index d75c8b9c..017dcdb7 100644 --- a/Funcky/PublicAPI.Unshipped.txt +++ b/Funcky/PublicAPI.Unshipped.txt @@ -11,10 +11,43 @@ Funcky.Monads.Result.OrElse(Funcky.Monads.Result fal Funcky.Monads.Result.OrElse(System.Func>! fallback) -> Funcky.Monads.Result Funcky.UpCast static Funcky.Extensions.EnumeratorExtensions.MoveNextOrNone(this System.Collections.Generic.IEnumerator! enumerator) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseByteOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseByteOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseByteOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDecimalOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDecimalOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDecimalOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDoubleOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDoubleOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseDoubleOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt16OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt16OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt16OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt32OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt32OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt32OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt64OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt64OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseInt64OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this string! value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this System.ReadOnlySpan value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseOrNone(this string? value, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseOrNone(this System.ReadOnlySpan value, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSingleOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSingleOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseSingleOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt16OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt16OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt16OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt32OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt32OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt32OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt64OrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt64OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseUInt64OrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option static Funcky.Extensions.StringExtensions.Chunk(this string! source, int size) -> System.Collections.Generic.IEnumerable! static Funcky.Extensions.StringExtensions.SlidingWindow(this string! source, int width) -> System.Collections.Generic.IEnumerable! static Funcky.UpCast.From(System.Lazy! lazy) -> System.Lazy! From d651c4ad1ceeb0b8ac322cb9a7d824cfc846f864 Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 21:42:11 +0100 Subject: [PATCH 6/7] Add generic parse method for IUtf8SpanParsable --- FrameworkFeatureConstants.props | 2 +- .../ParseExtensions.GenericParseable.cs | 12 ++++++++++-- Funcky/PublicAPI.Unshipped.txt | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/FrameworkFeatureConstants.props b/FrameworkFeatureConstants.props index cd17d346..15a19520 100644 --- a/FrameworkFeatureConstants.props +++ b/FrameworkFeatureConstants.props @@ -16,6 +16,6 @@ $(DefineConstants);GENERIC_MATH;GENERIC_PARSEABLE - $(DefineConstants);RANDOM_SHUFFLE + $(DefineConstants);RANDOM_SHUFFLE;UTF8_SPAN_PARSEABLE diff --git a/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs index d8cb3572..63a370da 100644 --- a/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs +++ b/Funcky/Extensions/ParseExtensions/ParseExtensions.GenericParseable.cs @@ -1,8 +1,8 @@ -#if GENERIC_PARSEABLE namespace Funcky.Extensions; public static partial class ParseExtensions { +#if GENERIC_PARSEABLE public static Option ParseOrNone(this ReadOnlySpan value, IFormatProvider? provider) where TParseable : ISpanParsable => TParseable.TryParse(value, provider, out var result) @@ -14,5 +14,13 @@ public static Option ParseOrNone(this string? value, IFo => TParseable.TryParse(value, provider, out var result) ? result : Option.None; -} #endif + +#if UTF8_SPAN_PARSEABLE + public static Option ParseOrNone(this ReadOnlySpan utf8Text, IFormatProvider? provider) + where TParseable : IUtf8SpanParsable + => TParseable.TryParse(utf8Text, provider, out var result) + ? result + : Option.None; +#endif +} diff --git a/Funcky/PublicAPI.Unshipped.txt b/Funcky/PublicAPI.Unshipped.txt index 017dcdb7..7c28104c 100644 --- a/Funcky/PublicAPI.Unshipped.txt +++ b/Funcky/PublicAPI.Unshipped.txt @@ -33,6 +33,7 @@ static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this string! static Funcky.Extensions.ParseExtensions.ParseNumberOrNone(this System.ReadOnlySpan value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseOrNone(this string? value, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseOrNone(this System.ReadOnlySpan value, System.IFormatProvider? provider) -> Funcky.Monads.Option +static Funcky.Extensions.ParseExtensions.ParseOrNone(this System.ReadOnlySpan utf8Text, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate, System.Globalization.NumberStyles style, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option From 74385e6886cc6920c0308617decb3c88d80575d4 Mon Sep 17 00:00:00 2001 From: Tau <4602612+bash@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:23:00 +0100 Subject: [PATCH 7/7] Update `Materialize` tests to account for new optimization --- .../EnumerableExtensions/AnyOrElseTest.cs | 6 +++--- .../GetNonEnumeratedCountOrNoneTest.cs | 2 +- .../EnumerableExtensions/MaterializeTest.cs | 15 +++++++++++++-- Funcky.Test/TestUtils/EnumerableExtensions.cs | 5 ++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Funcky.Test/Extensions/EnumerableExtensions/AnyOrElseTest.cs b/Funcky.Test/Extensions/EnumerableExtensions/AnyOrElseTest.cs index a2e2ff9e..53d1c71a 100644 --- a/Funcky.Test/Extensions/EnumerableExtensions/AnyOrElseTest.cs +++ b/Funcky.Test/Extensions/EnumerableExtensions/AnyOrElseTest.cs @@ -13,7 +13,7 @@ public void IsEmptyWhenBothEnumerablesAreEmpty() [Fact] public void IsSourceEnumerableWhenNonEmpty() { - var source = Sequence.Return(1, 2, 3).EraseNonEnumeratedCount(); + var source = Sequence.Return(1, 2, 3).PreventLinqOptimizations(); var fallback = Sequence.Return(4, 5, 6); Assert.Equal(source, source.AnyOrElse(fallback)); } @@ -21,7 +21,7 @@ public void IsSourceEnumerableWhenNonEmpty() [Fact] public void IsFallbackEnumerableWhenSourceIsEmpty() { - var source = Enumerable.Empty().EraseNonEnumeratedCount(); + var source = Enumerable.Empty().PreventLinqOptimizations(); var fallback = Sequence.Return(1, 2, 3); Assert.Equal(fallback, source.AnyOrElse(fallback)); } @@ -36,7 +36,7 @@ public void SourceIsEnumeratedLazily() [Fact] public void FallbackIsEnumeratedLazily() { - var source = Enumerable.Empty().EraseNonEnumeratedCount(); + var source = Enumerable.Empty().PreventLinqOptimizations(); _ = source.AnyOrElse(new FailOnEnumerationSequence()); } diff --git a/Funcky.Test/Extensions/EnumerableExtensions/GetNonEnumeratedCountOrNoneTest.cs b/Funcky.Test/Extensions/EnumerableExtensions/GetNonEnumeratedCountOrNoneTest.cs index 54bef9df..2b6e1097 100644 --- a/Funcky.Test/Extensions/EnumerableExtensions/GetNonEnumeratedCountOrNoneTest.cs +++ b/Funcky.Test/Extensions/EnumerableExtensions/GetNonEnumeratedCountOrNoneTest.cs @@ -28,7 +28,7 @@ public void GetNonEnumeratedCountOrNoneReturnsCountOnEnumerableRange() [Property] public Property GetNonEnumeratedCountOrNoneReturnsNoneForInstancesWithoutCount(List list) { - return list.EraseNonEnumeratedCount().GetNonEnumeratedCountOrNone() + return list.PreventLinqOptimizations().GetNonEnumeratedCountOrNone() .Match(none: true, some: False) .ToProperty(); } diff --git a/Funcky.Test/Extensions/EnumerableExtensions/MaterializeTest.cs b/Funcky.Test/Extensions/EnumerableExtensions/MaterializeTest.cs index 5b9fcd73..1135d1bc 100644 --- a/Funcky.Test/Extensions/EnumerableExtensions/MaterializeTest.cs +++ b/Funcky.Test/Extensions/EnumerableExtensions/MaterializeTest.cs @@ -26,7 +26,7 @@ public void MaterializeDoesNotEnumerateCollectionTypes() [Fact] public void MaterializeReturnsImmutableCollectionWhenEnumerated() { - var sequence = Enumerable.Repeat("Hello world!", 3); + var sequence = Enumerable.Repeat("Hello world!", 3).PreventLinqOptimizations(); Assert.IsType>(sequence.Materialize()); } @@ -34,11 +34,22 @@ public void MaterializeReturnsImmutableCollectionWhenEnumerated() [Fact] public void MaterializeWithMaterializationReturnsCorrectCollectionWhenEnumerate() { - var sequence = Enumerable.Repeat("Hello world!", 3); + var sequence = Enumerable.Repeat("Hello world!", 3).PreventLinqOptimizations(); Assert.IsType>(sequence.Materialize(ToHashSet)); } +#if NET8_0_OR_GREATER + // This is an optimization added in .NET 8 + [Fact] + public void MaterializeDoesNotEnumerableEnumerableReturnedByRepeat() + { + var sequence = Enumerable.Repeat("Hello world!", 3); + var materialized = sequence.Materialize>(_ => throw new FailException("Materialization should never be called")); + Assert.Same(sequence, materialized); + } +#endif + [Fact] public void MaterializeDoesNotEnumerateCollectionWhichImplementsICollectionOnly() { diff --git a/Funcky.Test/TestUtils/EnumerableExtensions.cs b/Funcky.Test/TestUtils/EnumerableExtensions.cs index 97873c08..33b78295 100644 --- a/Funcky.Test/TestUtils/EnumerableExtensions.cs +++ b/Funcky.Test/TestUtils/EnumerableExtensions.cs @@ -2,10 +2,9 @@ namespace Funcky.Test.TestUtils; internal static class EnumerableExtensions { - internal static IEnumerable EraseNonEnumeratedCount(this IEnumerable source) + /// Prevents LINQ from optimizing by hiding the underlying source enumerable. + internal static IEnumerable PreventLinqOptimizations(this IEnumerable source) { - // Having our own state machine erases the non enumerated count - // provided when using LINQ methods such as Select. foreach (var element in source) { yield return element;