From 83a5383ac19056ce85b8ac5a9b581eaa0ca88b4f Mon Sep 17 00:00:00 2001 From: Jimmy Byrd Date: Sat, 7 Dec 2024 15:57:21 -0500 Subject: [PATCH] V5 2 (#284) * Remove Ply and update to FSharp 6 (#248) * remove Ply and update to FSharp 6 * Cleanup dependencies * Fix fsharp.core warning * Don't build so much * Asyncinterfaces (#250) * use Microsoft.Bcl.AsyncInterfaces * Updated IcedTasks to 0.11.0 * Fix for fable * Net8 (#251) * net8 tfm * Update README * Fix CI cancellation issues * Build on macos-14 * 205 overload resolution (#252) * Missed this in net8 additions * Fix overload resolution issues in Core * Fix overload resolution issues in Tasks/Hopac * Fix overload resolution issues in CancellableTaskResult * WIP: TaskValidtionCE * Wip merge sources * Fix MergeSources for CTValidation * cleanup * Ensure IAsyncDisposable tests * ignore nuget stuff * feat(Seq)!: Add sequenceResultA, align sequenceResultM (#255) * Roll on '24 * refactor(Seq.sequenceResultM)!: Change Ok to Array * docs: sequenceResultM * feat(Seq): sequenceResultA * f sequenceResultM docs * Supress compile error * Fix proposed version * Cleanup build * 209 remove MergeSources (and!) from some implementations (#261) * Remove MergeSources from resultCE * Remove MergeSources from AsyncResult * Remove MergeSources from ResultOption * Fixup resultOption docs * Remove MergeSources from OptionCE * Remove MergeSources from ValueOptionCE * remove MergeSources Option/ValueOption * MSBuild.StructuredLogger update * disable binlog for fake * Many updates * fix residual rebase artifacts * Merge TaskResult into Core lib (#285) * silence FS3511 --------- Co-authored-by: Ruben Bartelink --- .config/dotnet-tools.json | 2 +- .devcontainer/devcontainer.json | 4 +- .github/workflows/build.yml | 23 +- .paket/Paket.Restore.targets | 997 ++++----- Directory.Build.props | 12 +- FsToolkit.ErrorHandling.sln | 15 - README.md | 3 +- RELEASE_NOTES.md | 10 + benchmarks/ApplicativeTests.fs | 55 - benchmarks/benchmarks.fsproj | 4 +- build/build.fs | 83 +- build/build.fsproj | 22 +- gitbook/list/sequenceResultA.md | 2 +- gitbook/resultOption/ce.md | 4 +- gitbook/seq/sequenceResultA.md | 44 +- gitbook/seq/sequenceResultM.md | 39 +- global.json | 4 +- paket.dependencies | 44 +- paket.lock | 238 +-- playground.fsx | 305 +++ src/Directory.Build.props | 2 +- .../paket.references | 8 +- .../CancellableTaskResultBuilderBase.fs | 1379 ++++++++++++ .../CancellableTaskResultCE.fs | 907 +++----- .../CancellableTaskValidationCE.fs | 1851 ++++++++--------- .../FsToolkit.ErrorHandling.IcedTasks.fsproj | 39 +- .../paket.references | 7 +- .../FsToolkit.ErrorHandling.JobResult.fsproj | 52 +- .../JobOptionCE.fs | 34 +- .../JobResultCE.fs | 33 +- .../paket.references | 8 +- .../AssemblyInfo.fs | 19 - .../FsToolkit.ErrorHandling.TaskResult.fsproj | 32 - .../List.fs | 64 - .../Result.fs | 17 - .../paket.references | 4 - src/FsToolkit.ErrorHandling/AsyncOptionCE.fs | 27 +- src/FsToolkit.ErrorHandling/AsyncResultCE.fs | 36 +- .../AsyncResultOptionCE.fs | 38 +- .../FsToolkit.ErrorHandling.fsproj | 116 +- src/FsToolkit.ErrorHandling/List.fs | 59 + src/FsToolkit.ErrorHandling/OptionCE.fs | 41 +- src/FsToolkit.ErrorHandling/Result.fs | 14 + src/FsToolkit.ErrorHandling/ResultCE.fs | 7 - src/FsToolkit.ErrorHandling/ResultOptionCE.fs | 7 - src/FsToolkit.ErrorHandling/Seq.fs | 4 +- src/FsToolkit.ErrorHandling/Shims.fs | 22 - .../Task.fs | 6 +- .../TaskOp.fs | 0 .../TaskOption.fs | 4 +- .../TaskOptionCE.fs | 447 +--- .../TaskOptionOp.fs | 0 .../TaskResult.fs | 5 +- .../TaskResultCE.fs | 509 +---- .../TaskResultOp.fs | 0 .../TaskResultOption.fs | 2 +- .../TaskResultOptionCE.fs | 48 +- .../TaskResultOptionOp.fs | 0 src/FsToolkit.ErrorHandling/ValueOptionCE.fs | 34 +- src/FsToolkit.ErrorHandling/paket.references | 8 +- ...oolkit.ErrorHandling.AsyncSeq.Tests.fsproj | 43 +- .../paket.references | 1 + .../CancellableTaskResultCE.fs | 14 + .../CancellableTaskValidationCE.fs | 344 ++- .../Expect.fs | 4 - ...olkit.ErrorHandling.IcedTasks.Tests.fsproj | 43 +- .../paket.references | 9 +- ...olkit.ErrorHandling.JobResult.Tests.fsproj | 69 +- .../JobOptionCE.fs | 13 + .../JobResultCE.fs | 13 + .../JobResultOption.fs | 12 + .../paket.references | 2 +- .../BackgroundTaskOptionCE.fs | 16 +- .../BackgroundTaskResultCE.fs | 16 +- ...lkit.ErrorHandling.TaskResult.Tests.fsproj | 65 +- .../List.fs | 5 - .../Result.fs | 3 - .../TaskOption.fs | 3 - .../TaskOptionCE.fs | 97 +- .../TaskResult.fs | 4 - .../TaskResultCE.fs | 110 +- .../TaskResultOption.fs | 13 + .../paket.references | 2 +- .../AsyncOptionCE.fs | 35 +- .../AsyncResultCE.fs | 207 +- .../AsyncResultOptionCE.fs | 34 +- tests/FsToolkit.ErrorHandling.Tests/Expect.fs | 5 - .../FsToolkit.ErrorHandling.Tests.fsproj | 12 +- .../FsToolkit.ErrorHandling.Tests/OptionCE.fs | 225 +- .../FsToolkit.ErrorHandling.Tests/ResultCE.fs | 101 +- .../ResultOptionCE.fs | 101 +- .../TestHelpers.fs | 13 + .../ValueOptionCE.fs | 224 +- .../paket.references | 2 +- tools/FunctionMap/FunctionMap.fsproj | 36 +- tools/FunctionMap/paket.references | 3 +- 96 files changed, 4785 insertions(+), 4914 deletions(-) create mode 100644 playground.fsx create mode 100644 src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultBuilderBase.fs delete mode 100644 src/FsToolkit.ErrorHandling.TaskResult/AssemblyInfo.fs delete mode 100644 src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj delete mode 100644 src/FsToolkit.ErrorHandling.TaskResult/List.fs delete mode 100644 src/FsToolkit.ErrorHandling.TaskResult/Result.fs delete mode 100644 src/FsToolkit.ErrorHandling.TaskResult/paket.references delete mode 100644 src/FsToolkit.ErrorHandling/Shims.fs rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/Task.fs (96%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskOp.fs (100%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskOption.fs (98%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskOptionCE.fs (60%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskOptionOp.fs (100%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResult.fs (99%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResultCE.fs (57%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResultOp.fs (100%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResultOption.fs (93%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResultOptionCE.fs (88%) rename src/{FsToolkit.ErrorHandling.TaskResult => FsToolkit.ErrorHandling}/TaskResultOptionOp.fs (100%) create mode 100644 tests/FsToolkit.ErrorHandling.Tests/TestHelpers.fs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 58f9e8bf..3c257a01 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "paket": { - "version": "8.0.0", + "version": "8.0.3", "commands": [ "paket" ] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 08b84193..0882c721 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -23,8 +23,8 @@ "ghcr.io/devcontainers-contrib/features/starship:1": {}, // https://github.com/devcontainers/features/blob/main/src/dotnet/README.md "ghcr.io/devcontainers/features/dotnet:2": { - "version": "7.0", - "additionalVersions": "6.0" + "version": "8.0", + "additionalVersions": "7.0,6.0" }, "ghcr.io/devcontainers/features/node:1": { "version": "18" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0491abba..551d6481 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,14 @@ name: Build master -on: [push, pull_request] +on: + # Runs only on pushes to the default branch or pull requests to the default branch + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: jobs: @@ -12,7 +20,7 @@ jobs: # Builds for Debug and Release configurations configuration: [Debug, Release] # Builds for Ubuntu, Windows, and macOS - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest, macos-14] runs-on: ${{ matrix.os }} steps: @@ -22,6 +30,8 @@ jobs: with: global-json-file: global.json dotnet-version: | + 8.x + 7.x 6.x - name: Build via Bash @@ -44,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest, macos-14] node-version: ['18', '20', 'latest' ] runs-on: ${{ matrix.os }} @@ -61,6 +71,8 @@ jobs: with: global-json-file: global.json dotnet-version: | + 8.x + 7.x 6.x - name: Build via Bash @@ -82,7 +94,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest, macos-14] python-version: ['3.10', '3.11', '3.12'] runs-on: ${{ matrix.os }} @@ -99,8 +111,9 @@ jobs: with: global-json-file: global.json dotnet-version: | + 8.x + 7.x 6.x - - name: Build via Bash if: runner.os != 'Windows' run: | diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets index 4deb15bc..bbeec153 100644 --- a/.paket/Paket.Restore.targets +++ b/.paket/Paket.Restore.targets @@ -1,322 +1,325 @@ - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - $(MSBuildVersion) - 15.0.0 - false - true - - true - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)..\ - $(PaketRootPath)paket-files\paket.restore.cached - $(PaketRootPath)paket.lock - classic - proj - assembly - native - /Library/Frameworks/Mono.framework/Commands/mono - mono - - - $(PaketRootPath)paket.bootstrapper.exe - $(PaketToolsPath)paket.bootstrapper.exe - $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\ - - "$(PaketBootStrapperExePath)" - $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" - - - - - true - true - - - True - - - False - - $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/')) - - - - - - - - - $(PaketRootPath)paket - $(PaketToolsPath)paket - - - - - - $(PaketRootPath)paket.exe - $(PaketToolsPath)paket.exe - - - - - - <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json")) - <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"')) - <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false - - - - - - - - - - - <_PaketCommand>dotnet paket - - - - - - $(PaketToolsPath)paket - $(PaketBootStrapperExeDir)paket - - - paket - - - - - <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) - <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)" - <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" - <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)" - - - - - - - - - - - - - - - - - - - - - true - $(NoWarn);NU1603;NU1604;NU1605;NU1608 - false - true - - - - - - - - - $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) - - - - - - - $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``)) - $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``)) - - - - - %(PaketRestoreCachedKeyValue.Value) - %(PaketRestoreCachedKeyValue.Value) - - - - - true - false - true - - - + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + $(MSBuildVersion) + 15.0.0 + false + true + + true + $(MSBuildThisFileDirectory) + $(MSBuildThisFileDirectory)..\ + $(PaketRootPath)paket-files\paket.restore.cached + $(PaketRootPath)paket.lock + classic + proj + assembly + native + /Library/Frameworks/Mono.framework/Commands/mono + mono + + + $(PaketRootPath)paket.bootstrapper.exe + $(PaketToolsPath)paket.bootstrapper.exe + $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\ + + "$(PaketBootStrapperExePath)" + $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" + + + + + true + true + + + True + + + False + + $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/')) + + + + + + + + + $(PaketRootPath)paket + $(PaketToolsPath)paket + + + + + + $(PaketRootPath)paket.exe + $(PaketToolsPath)paket.exe + + + + + + <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json")) + <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"')) + <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false + + + + + + + + + + + <_PaketCommand>dotnet paket + + + + + + $(PaketToolsPath)paket + $(PaketBootStrapperExeDir)paket + + + paket + + + + + <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)")) + <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)" + <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" + <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)" + + + + + + + + + + + + + + + + + + + + + true + $(NoWarn);NU1603;NU1604;NU1605;NU1608 + false + true + + + + + + + + + $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) + + + + + + + $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``)) + $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``)) + + + + + %(PaketRestoreCachedKeyValue.Value) + %(PaketRestoreCachedKeyValue.Value) + + + + + true + false + true + + + - - true - - - - - - - - - - - - - - - - - - - $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached - - $(MSBuildProjectFullPath).paket.references - - $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references - - $(MSBuildProjectDirectory)\paket.references - - false - true - true - references-file-or-cache-not-found - - - - - $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) - $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) - references-file - false - - - - - false - - - - - true - target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) - - - - - - - - - - - false - true - - - - - - - - - - - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[6]) - $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[7]) - - - %(PaketReferencesFileLinesInfo.PackageVersion) - All - runtime - $(ExcludeAssets);contentFiles - $(ExcludeAssets);build;buildMultitargeting;buildTransitive - true - true - - - - - $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools - - - - - - - - - $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) - $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) - - - %(PaketCliToolFileLinesInfo.PackageVersion) - - - - + + + + + + + + + + + + + + + + $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached + + $(MSBuildProjectFullPath).paket.references + + $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references + + $(MSBuildProjectDirectory)\paket.references + + false + true + true + references-file-or-cache-not-found + + + + + $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) + $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) + references-file + false + + + + + false + + + + + true + target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths) + + + + + + + + + + + false + true + + + + + + + + + + + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[6]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[7]) + $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[8]) + + + %(PaketReferencesFileLinesInfo.PackageVersion) + All + runtime + $(ExcludeAssets);contentFiles + $(ExcludeAssets);build;buildMultitargeting;buildTransitive + %(PaketReferencesFileLinesInfo.Aliases) + true + true + + + + + + $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools + + + + + + + + + $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) + $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) + + + %(PaketCliToolFileLinesInfo.PackageVersion) + + + + - - - - - false - - - - - - <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/> - - - - - - $(MSBuildProjectDirectory)/$(MSBuildProjectFile) - true - false - true - false - true - false - true - false - true - false - true - $(PaketIntermediateOutputPath)\$(Configuration) - $(PaketIntermediateOutputPath) - - - - <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/> - - - - - - - - - + + + + + false + + + + + + <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/> + + + + + + $(MSBuildProjectDirectory)/$(MSBuildProjectFile) + true + false + true + false + true + false + true + false + true + false + true + $(PaketIntermediateOutputPath)\$(Configuration) + $(PaketIntermediateOutputPath) + + + + <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/> + + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/Directory.Build.props b/Directory.Build.props index 67d20dab..f339b105 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,8 +1,8 @@ - - true - $(NoWarn);FS2003 - true - - + + true + $(NoWarn);FS2003; NU1903; NU1904 + true + + diff --git a/FsToolkit.ErrorHandling.sln b/FsToolkit.ErrorHandling.sln index aab8a780..f014a5d9 100644 --- a/FsToolkit.ErrorHandling.sln +++ b/FsToolkit.ErrorHandling.sln @@ -11,8 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D8B86171 EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.Tests", "tests\FsToolkit.ErrorHandling.Tests\FsToolkit.ErrorHandling.Tests.fsproj", "{F646F4E8-EA06-4EA8-9CD3-79778B264320}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.TaskResult", "src\FsToolkit.ErrorHandling.TaskResult\FsToolkit.ErrorHandling.TaskResult.fsproj", "{EA9FB942-F6A4-4539-9377-A2DBE73861FC}" -EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.TaskResult.Tests", "tests\FsToolkit.ErrorHandling.TaskResult.Tests\FsToolkit.ErrorHandling.TaskResult.Tests.fsproj", "{868CA980-5903-480E-8360-C51F5EC83275}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.JobResult", "src\FsToolkit.ErrorHandling.JobResult\FsToolkit.ErrorHandling.JobResult.fsproj", "{5B1EA296-538E-40E5-BF1D-6CB0F20BB52E}" @@ -72,18 +70,6 @@ Global {F646F4E8-EA06-4EA8-9CD3-79778B264320}.Release|x64.Build.0 = Release|Any CPU {F646F4E8-EA06-4EA8-9CD3-79778B264320}.Release|x86.ActiveCfg = Release|Any CPU {F646F4E8-EA06-4EA8-9CD3-79778B264320}.Release|x86.Build.0 = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|x64.ActiveCfg = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|x64.Build.0 = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|x86.ActiveCfg = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Debug|x86.Build.0 = Debug|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|Any CPU.Build.0 = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|x64.ActiveCfg = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|x64.Build.0 = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|x86.ActiveCfg = Release|Any CPU - {EA9FB942-F6A4-4539-9377-A2DBE73861FC}.Release|x86.Build.0 = Release|Any CPU {868CA980-5903-480E-8360-C51F5EC83275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {868CA980-5903-480E-8360-C51F5EC83275}.Debug|Any CPU.Build.0 = Debug|Any CPU {868CA980-5903-480E-8360-C51F5EC83275}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -220,7 +206,6 @@ Global GlobalSection(NestedProjects) = preSolution {E0466000-F8E4-416B-B605-C65F7602367A} = {E28025A7-EF6A-45BF-8FA0-75E394D3D42B} {F646F4E8-EA06-4EA8-9CD3-79778B264320} = {D8B86171-2147-49EF-8ADA-1CF8B0A20D40} - {EA9FB942-F6A4-4539-9377-A2DBE73861FC} = {E28025A7-EF6A-45BF-8FA0-75E394D3D42B} {868CA980-5903-480E-8360-C51F5EC83275} = {D8B86171-2147-49EF-8ADA-1CF8B0A20D40} {5B1EA296-538E-40E5-BF1D-6CB0F20BB52E} = {E28025A7-EF6A-45BF-8FA0-75E394D3D42B} {7DABAB8F-4A02-4992-A3A2-6C550F98C13B} = {D8B86171-2147-49EF-8ADA-1CF8B0A20D40} diff --git a/README.md b/README.md index 426c4ffd..8297cbd9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The library provides utility functions like `map`, `bind`, `apply`, `traverse`, It was inspired by [Chessie](https://github.com/fsprojects/Chessie) and Cvdm.ErrorHandling (the latter has now been merged into FsToolkit.ErrorHandling). -FsToolkit.ErrorHandling targets .NET Standard 2.0 and .NET Framework 4.6.1 and supports Fable. +FsToolkit.ErrorHandling targets .NET Standard 2.0, .NET Standard2.1 and supports Fable. ## Documentation @@ -47,6 +47,7 @@ This repository has a devcontainer setup for VSCode. For more infomation see: * [.NET Core SDK](https://www.microsoft.com/net/download/) * [v6.x](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) * [v7.x](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) + * [v8.x](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) #### Optional diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7b5e990e..40a44266 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,13 @@ +### 5.0.0-beta001 +- BREAKING: [Remove Ply and update to FSharp 6](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/248) Credits @TheAngryByrd +- BREAKING: [Remove MergeSources (and!) from some implementations](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/261) Credits @TheAngryByrd +- [Use Microsoft.Bcl.AsyncInterfaces in netstandard2.0 (Allows IAsyncDisposable and IAsyncEnumerable)](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/250) Credits @TheAngryByrd +- [Build against Net8](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/251) Credits @TheAngryByrd +- [Fix Overload Resolution to Align to Computation Expression used](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/252) Credits @TheAngryByrd +- [refactor!: Seq.sequenceResultM returns Array instead of seq](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/255) Credits @bartelink +- [feat(Seq): sequenceResultA](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/255) Credits @bartelink + + ### 4.18.0 - October 23, 2024 - [Add Array errorhandling](https://github.com/demystifyfp/FsToolkit.ErrorHandling/pull/279) Credits @DashieTM diff --git a/benchmarks/ApplicativeTests.fs b/benchmarks/ApplicativeTests.fs index 667dde0e..3b417a18 100644 --- a/benchmarks/ApplicativeTests.fs +++ b/benchmarks/ApplicativeTests.fs @@ -41,19 +41,6 @@ type Result_BindvsAndCEBenchmarks() = } |> ignore - [] - member this.All_Success_And() = - result { - let! r1 = successSlowSync this.delay - and! r2 = successSlowSync this.delay - and! r3 = successSlowSync this.delay - - return - r1 - + r2 - + r3 - } - |> ignore [] member this.Fail_First_Bind() = @@ -69,20 +56,6 @@ type Result_BindvsAndCEBenchmarks() = } |> ignore - [] - member this.Fail_First_And() = - result { - let! r1 = errorSlowSync this.delay - and! r2 = successSlowSync this.delay - and! r3 = successSlowSync this.delay - - return - r1 - + r2 - + r3 - } - |> ignore - [] member this.Fail_Mid_Bind() = result { @@ -97,20 +70,6 @@ type Result_BindvsAndCEBenchmarks() = } |> ignore - [] - member this.Fail_Mid_And() = - result { - let! r1 = successSlowSync this.delay - and! r2 = errorSlowSync this.delay - and! r3 = successSlowSync this.delay - - return - r1 - + r2 - + r3 - } - |> ignore - [] member this.Fail_Last_Bind() = result { @@ -124,17 +83,3 @@ type Result_BindvsAndCEBenchmarks() = + r3 } |> ignore - - [] - member this.Fail_Last_And() = - result { - let! r1 = successSlowSync this.delay - and! r2 = successSlowSync this.delay - and! r3 = errorSlowSync this.delay - - return - r1 - + r2 - + r3 - } - |> ignore diff --git a/benchmarks/benchmarks.fsproj b/benchmarks/benchmarks.fsproj index 99b4a122..d7827230 100644 --- a/benchmarks/benchmarks.fsproj +++ b/benchmarks/benchmarks.fsproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Exe preview @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/build/build.fs b/build/build.fs index 35f65c1b..7b62ef75 100644 --- a/build/build.fs +++ b/build/build.fs @@ -13,11 +13,30 @@ open System.IO open Fake.BuildServer open FsToolkit.Build +let environVarAsBoolOrDefault varName defaultValue = + let truthyConsts = [ + "1" + "Y" + "YES" + "T" + "TRUE" + ] + + try + let envvar = (Environment.environVar varName).ToUpper() + + truthyConsts + |> List.exists ((=) envvar) + with _ -> + defaultValue + let project = "FsToolkit.ErrorHandling" let summary = "FsToolkit.ErrorHandling is a utility library to work with the Result type in F#, and allows you to do clear, simple and powerful error handling." +let isCI = lazy (environVarAsBoolOrDefault "CI" false) + let isRelease (targets: Target list) = targets |> Seq.map (fun t -> t.Name) @@ -93,6 +112,18 @@ let failOnBadExitAndPrint (p: ProcessResult) = failwithf "failed with exitcode %d" p.ExitCode +// github actions are terrible and will cancel runner operations if using too much CPU +// https://github.com/actions/runner-images/discussions/7188#discussioncomment-6672934 +let maxCpuCount = lazy (if isCI.Value then Some(Some 2) else None) + +/// MaxCpu not used on unix https://github.com/fsprojects/FAKE/blob/82e38df01e4b31e5daa3623abff57e6462430395/src/app/Fake.DotNet.MSBuild/MSBuild.fs#L858-L861 +let maxCpuMsBuild = + lazy + (match maxCpuCount.Value with + | None -> "" + | Some None -> "/m" + | Some(Some x) -> $"/m:%d{x}") + module dotnet = let watch cmdParam program args = DotNet.exec cmdParam (sprintf "watch %s" program) args @@ -143,11 +174,24 @@ let clean _ = |> Seq.iter Shell.rm -let build ctx = - let setParams (defaults: DotNet.BuildOptions) = { +module BuildParameters = + let common (defaults: MSBuild.CliArguments) = { defaults with + DisableInternalBinLog = true + } + +let build ctx = + + let args = [ maxCpuMsBuild.Value ] + + let setParams (c: DotNet.BuildOptions) = { + c with NoRestore = true Configuration = (configuration ctx.Context.AllExecutingTargets) + MSBuildParams = BuildParameters.common c.MSBuildParams + Common = + c.Common + |> DotNet.Options.withAdditionalArgs args } DotNet.build setParams solutionFile @@ -159,14 +203,22 @@ let restore _ = ToolType = ToolType.CreateLocalTool() }) - DotNet.restore id solutionFile + let setParams (c: DotNet.RestoreOptions) = { + c with + MSBuildParams = BuildParameters.common c.MSBuildParams + } + + DotNet.restore setParams solutionFile let npmRestore _ = Npm.install id let dotnetTest ctx = - let args = [ "--no-build" ] + let args = [ + "--no-build" + maxCpuMsBuild.Value + ] DotNet.test (fun c -> @@ -177,6 +229,7 @@ let dotnetTest ctx = Common = c.Common |> DotNet.Options.withAdditionalArgs args + MSBuildParams = BuildParameters.common c.MSBuildParams }) solutionFile @@ -293,14 +346,16 @@ let dotnetPack ctx = // ./bin from the solution root matching the "PublishNuget" target WorkingDir OutputPath = Some distDir Configuration = configuration ctx.Context.AllExecutingTargets - MSBuildParams = { - MSBuild.CliArguments.Create() with - // "/p" (property) arguments to MSBuild.exe - Properties = [ - ("Version", release.NugetVersion) - ("PackageReleaseNotes", releaseNotes) - ] - } + MSBuildParams = + { + p.MSBuildParams with + // "/p" (property) arguments to MSBuild.exe + Properties = [ + ("Version", release.NugetVersion) + ("PackageReleaseNotes", releaseNotes) + ] + } + |> BuildParameters.common }) ) @@ -370,8 +425,8 @@ let initTargets () = BuildServer.install [ GitHubActions.Installer ] Option.iter (TraceSecrets.register "") githubToken.Value - Option.iter (TraceSecrets.register "") githubToken.Value - Option.iter (TraceSecrets.register "") githubToken.Value + Option.iter (TraceSecrets.register "") nugetToken.Value + Option.iter (TraceSecrets.register "") nugetToken.Value Target.create "Clean" clean diff --git a/build/build.fsproj b/build/build.fsproj index 8a227d7a..63f5f240 100644 --- a/build/build.fsproj +++ b/build/build.fsproj @@ -1,13 +1,13 @@  - - Exe - net7.0 - false - - - - - - - \ No newline at end of file + + Exe + net8.0 + false + + + + + + + diff --git a/gitbook/list/sequenceResultA.md b/gitbook/list/sequenceResultA.md index a2e0dacc..f904d42b 100644 --- a/gitbook/list/sequenceResultA.md +++ b/gitbook/list/sequenceResultA.md @@ -59,7 +59,7 @@ let checkIfAllPrime (numbers : int list) = numbers |> List.map isPrime // Result list |> List.sequenceResultA // Result - |> Result.map (List.forall id) // shortened version of '|> Result.map (fun boolList -> boolList |> List.map (fun x -> x = true))' + |> Result.map (List.forall id) // shortened version of '|> Result.map (fun boolList -> boolList |> List.forall (fun x -> x = true)) let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime // Error ["1 must be greater than 1"] diff --git a/gitbook/resultOption/ce.md b/gitbook/resultOption/ce.md index 8ccc5c84..2cd82b7e 100644 --- a/gitbook/resultOption/ce.md +++ b/gitbook/resultOption/ce.md @@ -25,8 +25,8 @@ let add x y z = x + y + z let addResult : Result = resultOption { let! x = Ok (Some 30) - and! y = Error "Oops 1" - and! z = Error "Oops 2" + let! y = Error "Oops 1" + let! z = Error "Oops 2" return add x y z } // Error "Oops 1" diff --git a/gitbook/seq/sequenceResultA.md b/gitbook/seq/sequenceResultA.md index 6364913a..60b6761b 100644 --- a/gitbook/seq/sequenceResultA.md +++ b/gitbook/seq/sequenceResultA.md @@ -5,11 +5,9 @@ Namespace: `FsToolkit.ErrorHandling` ## Function Signature ```fsharp -Result<'a, 'b> seq -> Result<'a seq, 'b seq> +seq> -> Result<'a[], 'b[]> ``` -Note that `sequence` is the same as `traverse id`. See also [Seq.traverseResultA](traverseResultA.md). - This is applicative, collecting all errors. Compare the example below with [sequenceResultM](sequenceResultM.md). See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpforfunandprofit.com/posts/elevated-world-4/). @@ -23,30 +21,27 @@ See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpfo let tryParseInt str = match Int32.TryParse str with | true, x -> Ok x - | false, _ -> - Error (sprintf "unable to parse '%s' to integer" str) + | false, _ -> Error $"unable to parse '{str}' to integer" ["1"; "2"; "3"] |> Seq.map tryParseInt |> Seq.sequenceResultA -// Ok [1; 2; 3] +// Ok [| 1; 2; 3 |] ["1"; "foo"; "3"; "bar"] |> Seq.map tryParseInt |> Seq.sequenceResultA -// Error ["unable to parse 'foo' to integer"; -// "unable to parse 'bar' to integer"] +// Error [| "unable to parse 'foo' to integer" +// "unable to parse 'bar' to integer" |] ``` ### Example 2 ```fsharp // int -> Result -let isPrime (x : int) = - if x < 2 then - sprintf "%i must be greater than 1" x |> Error - elif - x = 2 then Ok true +let isPrime (x: int) = + if x < 2 then Error $"{x} must be greater than 1" + elif x = 2 then Ok true else let rec isPrime' (x : int) (i : int) = if i * i > x then Ok true @@ -54,22 +49,21 @@ let isPrime (x : int) = else isPrime' x (i + 1) isPrime' x 2 -// int seq -> Result -let checkIfAllPrime (numbers : int seq) = - numbers - |> Seq.map isPrime // Result seq - |> Seq.sequenceResultA // Result - |> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun boolSeq -> boolSeq |> Seq.map (fun x -> x = true))' +// seq -> Result +let checkIfAllPrime (numbers: seq) = + seq { for x in numbers -> isPrime x } // Result seq + |> Seq.sequenceResultA // Result + |> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun results -> results |> Array.forall (fun x -> x = true))' -let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime -// Error ["1 must be greater than 1"] +let a = [| 1; 2; 3; 4; 5 |] |> checkIfAllPrime +// Error [| "1 must be greater than 1" |] -let b = [1; 2; 3; 4; 5; 0;] |> checkIfAllPrime -// Error ["1 must be greater than 1"; "0 must be greater than 1"] +let b = [ 1; 2; 3; 4; 5; 0 ] |> checkIfAllPrime +// Error [| "1 must be greater than 1"; "0 must be greater than 1" |] -let a = [2; 3; 4; 5;] |> checkIfAllPrime +let a = seq { 2; 3; 4; 5 } |> checkIfAllPrime // Ok false -let a = [2; 3; 5;] |> checkIfAllPrime +let a = seq { 2; 3; 5 } |> checkIfAllPrime // Ok true ``` diff --git a/gitbook/seq/sequenceResultM.md b/gitbook/seq/sequenceResultM.md index 4dddaa43..681bc0dd 100644 --- a/gitbook/seq/sequenceResultM.md +++ b/gitbook/seq/sequenceResultM.md @@ -5,11 +5,9 @@ Namespace: `FsToolkit.ErrorHandling` ## Function Signature ```fsharp -Result<'a, 'b> seq -> Result<'a seq, 'b> +seq> -> Result<'a[], 'b> ``` -Note that `sequence` is the same as `traverse id`. See also [Seq.traverseResultM](traverseResultM.md). - This is monadic, stopping on the first error. Compare the example below with [sequenceResultA](sequenceResultA.md). See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpforfunandprofit.com/posts/elevated-world-4/). @@ -23,15 +21,14 @@ See also Scott Wlaschin's [Understanding traverse and sequence](https://fsharpfo let tryParseInt str = match Int32.TryParse str with | true, x -> Ok x - | false, _ -> - Error (sprintf "unable to parse '%s' to integer" str) + | false, _ -> Error $"unable to parse '{str}' to integer" ["1"; "2"; "3"] |> Seq.map tryParseInt |> Seq.sequenceResultM -// Ok [1; 2; 3] +// Ok [| 1; 2; 3 |] -["1"; "foo"; "3"; "bar"] +seq { "1"; "foo"; "3"; "bar" } |> Seq.map tryParseInt |> Seq.sequenceResultM // Error "unable to parse 'foo' to integer" @@ -41,11 +38,9 @@ let tryParseInt str = ```fsharp // int -> Result -let isPrime (x : int) = - if x < 2 then - sprintf "%i must be greater than 1" x |> Error - elif - x = 2 then Ok true +let isPrime (x: int) = + if x < 2 then Error $"{x} must be greater than 1" + elif x = 2 then Ok true else let rec isPrime' (x : int) (i : int) = if i * i > x then Ok true @@ -53,20 +48,20 @@ let isPrime (x : int) = else isPrime' x (i + 1) isPrime' x 2 -// int seq -> Result -let checkIfAllPrime (numbers : int seq) = +// int seq -> Result +let checkIfAllPrime (numbers: seq) = numbers - |> Seq.map isPrime // Result seq - |> Seq.sequenceResultM // Result - |> Result.map (Seq.forall id) // shortened version of '|> Result.map (fun boolSeq -> boolSeq |> Seq.map (fun x -> x = true))'; + |> Seq.map isPrime // seq> + |> Seq.sequenceResultM // Result + |> Result.map (Array.forall id) // shortened version of '|> Result.map (fun bools -> bools |> Array.forall (fun x -> x = true))' -let a = [1; 2; 3; 4; 5;] |> checkIfAllPrime -// Error ["1 must be greater than 1"] +let a = [ 1; 2; 3; 4; 5 ] |> checkIfAllPrime +// Error [| "1 must be greater than 1" |] -let b = [1; 2; 3; 4; 5; 0;] |> checkIfAllPrime -// Error ["1 must be greater than 1"] +let b = [| 1; 2; 3; 4; 5; 0 |] |> checkIfAllPrime +// Error [| "1 must be greater than 1" |] -let a = [2; 3; 4; 5;] |> checkIfAllPrime +let a = seq { 2; 3; 4; 5 } |> checkIfAllPrime // Ok false let a = [2; 3; 5;] |> checkIfAllPrime diff --git a/global.json b/global.json index f3980d49..a53d9835 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.201", + "version": "8.0.100", "rollForward": "latestMinor" } -} +} \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies index 313f1028..43e61393 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -1,40 +1,15 @@ source https://api.nuget.org/v3/index.json - storage: none - -nuget Microsoft.SourceLink.GitHub prerelease copy_local: true - - - - -group NetStandard2 -source https://api.nuget.org/v3/index.json lowest_matching: true strategy: min -nuget FSharp.Core >= 4.7.2 -nuget Ply -nuget Hopac -nuget FSharp.Control.AsyncSeq +nuget FSharp.Core >= 6.0.1 +nuget Hopac >= 0.5.1 +nuget FSharp.Control.AsyncSeq >= 3.2.1 nuget Fable.Core >= 4.2.0 -framework: netstandard2.0, net6.0 -storage: none -condition: netstandard2_0 - - - - -group NetStandard2_1 -source https://api.nuget.org/v3/index.json -lowest_matching: true -strategy: min -nuget FSharp.Core >= 7.0.0 -nuget Hopac -nuget FSharp.Control.AsyncSeq -nuget IcedTasks >= 0.7.0 -framework: netstandard2.1, net7.0 -storage: none -condition: netstandard2_1 +nuget IcedTasks >= 0.11.4 +nuget Microsoft.SourceLink.GitHub prerelease copy_local: true +nuget Microsoft.Bcl.AsyncInterfaces >= 6.0.0 framework:netstandard2.0 group Test source https://api.nuget.org/v3/index.json @@ -50,7 +25,7 @@ nuget Fable.Core nuget Fable.Mocha nuget Fable.Python nuget Fable.Pyxpecto -nuget Ply +nuget Microsoft.Bcl.AsyncInterfaces >= 6.0.0 group Benchmarks source https://api.nuget.org/v3/index.json @@ -76,5 +51,8 @@ group Build nuget Fake.JavaScript.Npm 5.22.0 nuget Fake.Api.GitHub 5.22.0 nuget Fake.BuildServer.GitHubActions 5.22.0 - nuget MSBuild.StructuredLogger + nuget MSBuild.StructuredLogger 2.2.206 nuget Octokit + nuget Nuget.Common >= 6.6.1 + nuget NuGet.Protocol >= 6.6.1 + nuget System.Security.Cryptography.Pkcs >= 7.0.2 diff --git a/paket.lock b/paket.lock index 73301972..8115e906 100644 --- a/paket.lock +++ b/paket.lock @@ -1,11 +1,28 @@ STORAGE: NONE +STRATEGY: MIN +LOWEST_MATCHING: TRUE NUGET remote: https://api.nuget.org/v3/index.json + Fable.Core (4.2) + FSharp.Control.AsyncSeq (3.2.1) + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 5.0) - restriction: >= netstandard2.0 + FSharp.Core (6.0.1) + Hopac (0.5.1) + FSharp.Core (>= 4.5.2) - restriction: >= netstandard2.0 + IcedTasks (0.11.4) + FSharp.Core (>= 6.0.1) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: && (>= netstandard2.0) (< netstandard2.1) + Microsoft.Bcl.AsyncInterfaces (6.0) - restriction: == netstandard2.0 + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net461) (&& (>= netstandard2.0) (< netstandard2.1)) Microsoft.Build.Tasks.Git (8.0) - copy_local: true Microsoft.SourceLink.Common (8.0) - copy_local: true Microsoft.SourceLink.GitHub (8.0) - copy_local: true Microsoft.Build.Tasks.Git (>= 8.0) Microsoft.SourceLink.Common (>= 8.0) + System.Runtime.CompilerServices.Unsafe (4.5.3) - restriction: == netstandard2.0 + System.Threading.Tasks.Extensions (4.5.4) - restriction: == netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< win8)) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= wp8) GROUP Benchmarks STORAGE: NONE @@ -737,153 +754,115 @@ NUGET FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 System.Reactive (>= 5.0) - restriction: >= netstandard2.0 FSharp.Core (6.0.3) - Microsoft.Build.Framework (17.0) - restriction: >= netstandard2.0 - System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) - Microsoft.Build.Utilities.Core (17.0) - restriction: >= netstandard2.0 - Microsoft.Build.Framework (>= 17.0) - restriction: >= netstandard2.0 - Microsoft.NET.StringTools (>= 1.0) - restriction: >= netstandard2.0 - Microsoft.VisualStudio.Setup.Configuration.Interop (>= 1.16.30) - restriction: >= net472 - Microsoft.Win32.Registry (>= 4.3) - restriction: && (< net472) (>= netstandard2.0) - System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 - System.Configuration.ConfigurationManager (>= 4.7) - restriction: >= netstandard2.0 - System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) - System.Text.Encoding.CodePages (>= 4.0.1) - restriction: && (< net472) (>= netstandard2.0) - Microsoft.NET.StringTools (1.0) - restriction: >= netstandard2.0 - System.Memory (>= 4.5.4) - restriction: >= netstandard2.0 - System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 - Microsoft.NETCore.Platforms (6.0.1) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (>= monoandroid) (>= netcoreapp2.1) (< netstandard1.3)) (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= net5.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinios)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarintvos)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinwatchos)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) (&& (>= netcoreapp2.1) (>= uap10.1)) + Microsoft.Bcl.AsyncInterfaces (8.0) - restriction: || (&& (>= net462) (>= netstandard2.0)) (>= net472) (&& (< net5.0) (>= netstandard2.0)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Build.Framework (17.9.5) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + System.Memory (>= 4.5.5) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net8.0) (>= netstandard2.0)) + System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + Microsoft.Build.Utilities.Core (17.9.5) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 17.9.5) - restriction: >= netstandard2.0 + Microsoft.IO.Redist (>= 6.0) - restriction: >= net472 + Microsoft.NET.StringTools (>= 17.9.5) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 5.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + System.Collections.Immutable (>= 8.0) - restriction: >= netstandard2.0 + System.Configuration.ConfigurationManager (>= 8.0) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net8.0) (>= netstandard2.0)) + System.Security.Principal.Windows (>= 5.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + System.Text.Encoding.CodePages (>= 7.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + Microsoft.IO.Redist (6.0) - restriction: >= net472 + System.Buffers (>= 4.5.1) - restriction: >= net472 + System.Memory (>= 4.5.4) - restriction: >= net472 + Microsoft.NET.StringTools (17.9.5) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.5) - restriction: || (>= net472) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net472) (&& (< net8.0) (>= netstandard2.0)) + Microsoft.NETCore.Platforms (6.0.1) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard2.0) (< win8) (< wpa81)) - Microsoft.VisualStudio.Setup.Configuration.Interop (3.1.2196) - restriction: >= net472 - Microsoft.Win32.Registry (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (&& (< net472) (>= netstandard2.0)) + Microsoft.Win32.Registry (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (&& (< net472) (< net8.0) (>= netstandard2.0)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) System.Security.AccessControl (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) - Microsoft.Win32.SystemEvents (6.0) - restriction: >= netcoreapp3.1 Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 - MSBuild.StructuredLogger (2.1.787) - Microsoft.Build.Framework (>= 16.10) - restriction: >= netstandard2.0 - Microsoft.Build.Utilities.Core (>= 16.10) - restriction: >= netstandard2.0 - Newtonsoft.Json (13.0.1) - restriction: >= netstandard2.0 - NuGet.Common (6.0) - restriction: >= netstandard2.0 - NuGet.Frameworks (>= 6.0) - restriction: || (>= net45) (>= netstandard2.0) - NuGet.Configuration (6.0) - restriction: >= netstandard2.0 - NuGet.Common (>= 6.0) - restriction: || (>= net45) (>= netstandard2.0) - System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net45) (>= netstandard2.0) - NuGet.Frameworks (6.0) - restriction: >= netstandard2.0 - NuGet.Packaging (6.0) - restriction: >= netstandard2.0 - Newtonsoft.Json (>= 13.0.1) - restriction: >= netstandard2.0 - NuGet.Configuration (>= 6.0) - restriction: >= netstandard2.0 - NuGet.Versioning (>= 6.0) - restriction: >= netstandard2.0 - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - NuGet.Protocol (6.0) - restriction: >= netstandard2.0 - NuGet.Packaging (>= 6.0) - restriction: >= netstandard2.0 - NuGet.Versioning (6.0) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.2.206) + Microsoft.Build.Framework (>= 17.5) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (>= 17.5) - restriction: >= netstandard2.0 + Newtonsoft.Json (13.0.3) - restriction: >= netstandard2.0 + NuGet.Common (6.8) + NuGet.Frameworks (>= 6.8) - restriction: >= netstandard2.0 + NuGet.Configuration (6.8) - restriction: >= netstandard2.0 + NuGet.Common (>= 6.8) - restriction: >= netstandard2.0 + System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) + NuGet.Frameworks (6.8) - restriction: >= netstandard2.0 + NuGet.Packaging (6.8) - restriction: >= netstandard2.0 + Newtonsoft.Json (>= 13.0.3) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 6.8) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 6.8) - restriction: >= netstandard2.0 + System.Security.Cryptography.Pkcs (>= 6.0.4) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (6.8) + NuGet.Packaging (>= 6.8) - restriction: >= netstandard2.0 + System.Text.Json (>= 7.0.3) - restriction: || (>= net472) (&& (< net5.0) (>= netstandard2.0)) + NuGet.Versioning (6.8) - restriction: >= netstandard2.0 Octokit (0.50) - System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.1)) (&& (< net461) (< net6.0) (>= netstandard2.0)) (&& (< net461) (>= netstandard2.0) (< netstandard2.1)) (&& (>= net5.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) - System.Collections.Immutable (6.0) - restriction: >= netstandard2.0 - System.Memory (>= 4.5.4) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net461) (>= netstandard2.0) - System.Configuration.ConfigurationManager (6.0) - restriction: >= netstandard2.0 - System.Security.Cryptography.ProtectedData (>= 6.0) - restriction: || (&& (< net461) (>= netstandard2.0)) (>= net6.0) - System.Security.Permissions (>= 6.0) - restriction: || (>= net461) (>= netstandard2.0) - System.Drawing.Common (6.0) - restriction: >= netcoreapp3.1 - Microsoft.Win32.SystemEvents (>= 6.0) - restriction: >= netcoreapp3.1 - System.Formats.Asn1 (6.0) - restriction: || (&& (< net461) (>= netstandard2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) - System.Buffers (>= 4.5.1) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Memory (>= 4.5.4) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.IO (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) - System.Memory (4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net5.0) (< netstandard2.1)) (>= netstandard2.0) + System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (< net462) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.1)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (< net5.0) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.1)) (&& (< net8.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net8.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net8.0) (>= xamarinios)) (&& (< net8.0) (>= xamarinmac)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (< netstandard2.1) (>= xamarintvos)) (&& (>= netstandard2.0) (< netstandard2.1) (>= xamarinwatchos)) (&& (< netstandard2.1) (>= xamarinios)) (&& (< netstandard2.1) (>= xamarinmac)) + System.Collections.Immutable (8.0) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) + System.Configuration.ConfigurationManager (8.0) - restriction: >= netstandard2.0 + System.Diagnostics.EventLog (>= 8.0) - restriction: >= net7.0 + System.Security.Cryptography.ProtectedData (>= 8.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (>= net6.0) + System.Diagnostics.EventLog (8.0) - restriction: >= net7.0 + System.Formats.Asn1 (8.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (>= netcoreapp3.0) (< xamarintvos) (< xamarinwatchos)) (>= netstandard2.1) + System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Memory (4.5.5) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.1)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net472) (&& (< net5.0) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net6.0) (>= netstandard2.1)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (>= uap10.1)) System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (< uap10.1) (>= wpa81)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) System.Numerics.Vectors (>= 4.4) - restriction: && (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Numerics.Vectors (>= 4.5) - restriction: >= net461 System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (>= monoandroid) (< netstandard1.1)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) - System.Numerics.Vectors (4.5) - restriction: || (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netstandard2.0)) + System.Numerics.Vectors (4.5) - restriction: && (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Reactive (5.0) - restriction: >= netstandard2.0 System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< netcoreapp3.1) (>= netstandard2.0)) (>= uap10.1) - System.Runtime (4.3.1) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.Runtime (4.3.1) - restriction: && (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) - System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (< monoandroid) (< netstandard1.1) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= netstandard2.0)) (>= net472) (&& (< net5.0) (>= net6.0)) (&& (< net5.0) (>= netstandard2.0)) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (< netstandard2.1) (>= xamarintvos)) (&& (>= netstandard2.0) (< netstandard2.1) (>= xamarinwatchos)) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= wp8)) (&& (< netstandard2.1) (>= xamarinios)) (&& (< netstandard2.1) (>= xamarinmac)) System.Runtime.InteropServices.WindowsRuntime (4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.AccessControl (6.0) - restriction: && (< net472) (>= netstandard2.0) + System.Security.AccessControl (6.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< net8.0) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (< net472) (>= netstandard2.0)) (&& (< net8.0) (>= netcoreapp2.1)) (&& (< net8.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net8.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net8.0) (>= xamarinios)) (&& (< net8.0) (>= xamarinmac)) (&& (>= netstandard2.0) (>= uap10.1)) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) - System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) - System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) - System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) - System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net461) (>= netstandard2.0) (< netstandard2.1)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (< net6.0) (>= netcoreapp3.1)) (&& (< netcoreapp3.1) (>= netstandard2.1)) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos) System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) - System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) - System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) - System.Security.Cryptography.Pkcs (6.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) - System.Buffers (>= 4.5.1) - restriction: && (< net461) (>= netstandard2.0) (< netstandard2.1) - System.Formats.Asn1 (>= 6.0) - restriction: || (&& (< net461) (>= netstandard2.0)) (>= netstandard2.1) - System.Memory (>= 4.5.4) - restriction: && (< net461) (>= netstandard2.0) (< netstandard2.1) - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net461) (>= netstandard2.0) (< netstandard2.1)) (&& (< net6.0) (>= netcoreapp3.1)) (&& (< netcoreapp3.1) (>= netstandard2.1)) - System.Security.Cryptography.Primitives (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) (&& (>= net47) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net47) (< netstandard1.6) (>= netstandard2.0)) - System.Security.Cryptography.ProtectedData (6.0) - restriction: || (&& (< net461) (>= netstandard2.0)) (>= net6.0) - System.Memory (>= 4.5.4) - restriction: && (< net461) (< net6.0) (>= netstandard2.0) - System.Security.Permissions (6.0) - restriction: >= netstandard2.0 - System.Security.AccessControl (>= 6.0) - restriction: || (>= net461) (>= netstandard2.0) - System.Windows.Extensions (>= 6.0) - restriction: >= netcoreapp3.1 - System.Security.Principal.Windows (5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (< net472) (>= netstandard2.0)) (&& (< net472) (< net6.0) (>= netstandard2.0)) (>= netcoreapp2.1) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + System.Security.Cryptography.Pkcs (8.0) + System.Buffers (>= 4.5.1) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) + System.Formats.Asn1 (>= 8.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (>= netstandard2.1) + System.Memory (>= 4.5.5) - restriction: && (< net462) (>= netstandard2.0) (< netstandard2.1) + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.1)) + System.Security.Cryptography.ProtectedData (8.0) - restriction: || (&& (< net462) (>= netstandard2.0)) (&& (< net472) (>= netstandard2.0)) (>= net6.0) + System.Memory (>= 4.5.5) - restriction: && (< net462) (< net6.0) (>= netstandard2.0) + System.Security.Principal.Windows (5.0) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< net6.0) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (>= net461) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (< net472) (>= netstandard2.0)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= net461) (>= netstandard2.0) (>= xamarintvos)) (&& (>= net461) (>= netstandard2.0) (>= xamarinwatchos)) (&& (>= net461) (>= xamarinios)) (&& (>= net461) (>= xamarinmac)) (&& (< net472) (< net8.0) (>= netstandard2.0)) (&& (< net6.0) (>= netcoreapp2.1)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (>= netstandard2.0) (>= uap10.1)) Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) - System.Text.Encoding.CodePages (6.0) - restriction: && (< net472) (>= netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (>= net461) (&& (< netcoreapp3.1) (>= netstandard2.0)) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net461) (>= netstandard2.0) - System.Threading.Tasks.Extensions (4.5.4) - restriction: || (>= net472) (&& (< netcoreapp3.1) (>= netstandard2.0)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Text.Encoding.CodePages (8.0) - restriction: && (< net472) (< net8.0) (>= netstandard2.0) + System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) + System.Text.Encodings.Web (8.0) - restriction: || (&& (>= net462) (>= netstandard2.0)) (>= net472) (&& (< net5.0) (>= netstandard2.0)) + System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) + System.Text.Json (8.0.1) - restriction: || (>= net472) (&& (< net5.0) (>= netstandard2.0)) + Microsoft.Bcl.AsyncInterfaces (>= 8.0) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Buffers (>= 4.5.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) + System.Text.Encodings.Web (>= 8.0) - restriction: || (>= net462) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) + System.ValueTuple (>= 4.5) - restriction: >= net462 + System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (>= net462) (>= netstandard2.0)) (>= net472) (&& (< net5.0) (>= netstandard2.0)) (&& (< netcoreapp3.1) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) (&& (>= netstandard2.0) (>= uap10.1)) System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< win8)) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= wp8) - System.ValueTuple (4.5) - restriction: && (>= net45) (>= netstandard2.0) - System.Windows.Extensions (6.0) - restriction: >= netcoreapp3.1 - System.Drawing.Common (>= 6.0) - restriction: >= netcoreapp3.1 - -GROUP NetStandard2 -STORAGE: NONE -STRATEGY: MIN -LOWEST_MATCHING: TRUE -CONDITION: NETSTANDARD2_0 -RESTRICTION: || (== net6.0) (== netstandard2.0) -NUGET - remote: https://api.nuget.org/v3/index.json - Fable.Core (4.2) - FSharp.Control.AsyncSeq (3.2.1) - FSharp.Core (>= 4.7.2) - Microsoft.Bcl.AsyncInterfaces (>= 5.0) - FSharp.Core (4.7.2) - Hopac (0.5.1) - FSharp.Core (>= 4.5.2) - Microsoft.Bcl.AsyncInterfaces (6.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) - Ply (0.3.1) - FSharp.Core (>= 4.6.2) - System.Threading.Tasks.Extensions (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (== netstandard2.0) - System.Threading.Tasks.Extensions (4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (== netstandard2.0) - -GROUP NetStandard2_1 -STORAGE: NONE -STRATEGY: MIN -LOWEST_MATCHING: TRUE -CONDITION: NETSTANDARD2_1 -RESTRICTION: || (== net7.0) (== netstandard2.1) -NUGET - remote: https://api.nuget.org/v3/index.json - FSharp.Control.AsyncSeq (3.2.1) - FSharp.Core (>= 4.7.2) - Microsoft.Bcl.AsyncInterfaces (>= 5.0) - FSharp.Core (7.0.300) - Hopac (0.5.1) - FSharp.Core (>= 4.5.2) - IcedTasks (0.7) - FSharp.Core (>= 7.0) - Microsoft.Bcl.AsyncInterfaces (6.0) + System.ValueTuple (4.5) - restriction: || (&& (>= net462) (>= netstandard2.0)) (>= net472) GROUP Test STORAGE: NONE @@ -911,6 +890,8 @@ NUGET FSharp.Core (7.0.402) Hopac (0.5.1) - restriction: >= net6.0 FSharp.Core (>= 4.5.2) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (6.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net461) (&& (>= netstandard2.0) (< netstandard2.1)) Microsoft.CodeCoverage (17.8) - restriction: || (>= net462) (>= netcoreapp3.1) Microsoft.NET.Test.Sdk (17.8) Microsoft.CodeCoverage (>= 17.8) - restriction: || (>= net462) (>= netcoreapp3.1) @@ -924,9 +905,6 @@ NUGET Mono.Cecil (0.11.5) - restriction: >= net6.0 Newtonsoft.Json (13.0.3) - restriction: >= netcoreapp3.1 NuGet.Frameworks (6.8) - restriction: >= netcoreapp3.1 - Ply (0.3.1) - FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: >= netstandard2.0 System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard2.0)) (&& (>= monotouch) (>= netcoreapp3.1)) (&& (>= net45) (>= netcoreapp3.1) (< netstandard2.0)) (&& (>= net461) (>= netcoreapp3.1)) (&& (>= net462) (>= netcoreapp3.1)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinios)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinmac)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarintvos)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinwatchos)) (&& (< netcoreapp2.0) (>= netcoreapp3.1)) (&& (>= netcoreapp3.1) (< netstandard1.1) (>= win8)) (&& (>= netcoreapp3.1) (< netstandard2.0) (>= wpa81)) System.Collections.Immutable (8.0) - restriction: >= netcoreapp3.1 System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (>= net462) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netstandard2.0)) @@ -936,8 +914,8 @@ NUGET System.Reflection.Metadata (8.0) - restriction: >= netcoreapp3.1 System.Collections.Immutable (>= 8.0) - restriction: || (>= net462) (>= netstandard2.0) System.Memory (>= 4.5.5) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) - System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (>= monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (< netcoreapp2.1) (>= netcoreapp3.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard2.0)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netcoreapp3.1)) (&& (>= net45) (>= netcoreapp3.1) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp3.1)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netcoreapp3.1)) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinios)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinmac)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarintvos)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinwatchos)) (&& (< netcoreapp2.0) (>= netcoreapp3.1)) (&& (>= netcoreapp3.1) (< netstandard1.1) (>= win8)) (&& (>= netcoreapp3.1) (< netstandard2.0) (>= wpa81)) (&& (>= netcoreapp3.1) (>= uap10.1)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= wp8)) - System.Threading.Tasks.Extensions (4.5.4) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (>= monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (< netcoreapp2.1) (>= netcoreapp3.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard1.1)) (&& (< monoandroid) (>= netcoreapp3.1) (< netstandard2.0)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netcoreapp3.1)) (&& (>= net45) (>= netcoreapp3.1) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1) (< xamarintvos) (< xamarinwatchos)) (>= net461) (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netcoreapp3.1)) (&& (>= net6.0) (< net7.0)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinios)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinmac)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarintvos)) (&& (< net6.0) (>= netcoreapp3.1) (>= xamarinwatchos)) (&& (< netcoreapp2.0) (>= netcoreapp3.1)) (&& (>= netcoreapp3.1) (< netstandard1.1) (>= win8)) (&& (>= netcoreapp3.1) (< netstandard2.0) (>= wpa81)) (&& (>= netcoreapp3.1) (>= uap10.1)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= wp8)) + System.Threading.Tasks.Extensions (4.5.4) - restriction: || (>= net461) (&& (>= netstandard2.0) (< netstandard2.1)) System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< win8)) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= wp8) YoloDev.Expecto.TestSdk (0.14.3) Expecto (>= 10.0 < 11.0) - restriction: >= net6.0 diff --git a/playground.fsx b/playground.fsx new file mode 100644 index 00000000..f3772be8 --- /dev/null +++ b/playground.fsx @@ -0,0 +1,305 @@ +#r "nuget: FsToolkit.ErrorHandling.TaskResult" + +let inline id x = x + +open FsToolkit.ErrorHandling + +Result.ofChoice +module Operators = + + let inline bindM builder m ([] f) = + (^M: (member Bind: 'd -> ('e -> 'c) -> 'c) (builder, m, f)) + + let inline bind2M builder m1 m2 f = + (^M: (member Bind2: 'a -> 'b -> ('e * 'f -> 'c) -> 'c) (builder, m1, m2, f)) + + let inline delayM builder x = + (^M: (member Delay: (unit -> 'a) -> 'c) (builder, x)) + + /// Inject a value into the monadic type + let inline returnM builder x = + (^M: (member Return: 'b -> 'c) (builder, x)) + + let inline returnFromM builder x = + (^M: (member ReturnFrom: 'b -> 'c) (builder, x)) + + let inline bindReturnM builder m ([] f) = + (^M: (member BindReturn: 'd -> ('e -> 'c) -> 'f) (builder, m, f)) + + let inline bind2ReturnM builder m1 m2 ([] f) = + (^M: (member Bind2Return: 'a -> 'b -> ('c * 'd -> 'e) -> 'f) (builder, m1, m2, f)) + + let inline mergeSourcesM builder m1 m2 = + (^M: (member MergeSources: 'a * 'b -> 'c) (builder, m1, m2)) + + let inline mergeSources3M builder m1 m2 m3 = + (^M: (member MergeSources3: 'a * 'b * 'c -> 'd) (builder, m1, m2, m3)) + + let inline liftM builder m ([] f) = + bindM builder m + <| fun m1 -> returnM builder (f m1) + + let inline lift2M builder1 builder2 m1 m2 ([] f) = + bindM builder1 m1 + <| fun m1' -> + liftM builder2 m2 + <| fun m2' -> (f m1' m2') + + /// Sequential application + let inline applyM (builder1: ^M1) (builder2: ^M2) f m = + lift2M builder1 builder2 f m + <| fun f x -> f x + + /// Sequential application + let inline zipM (builder1: ^M1) (builder2: ^M2) m1 m2 = + lift2M builder1 builder2 m1 m2 + <| fun m1' m2' -> (m1', m2') + + +module Async = + let inline bind ([] f) x = Operators.bindM async x f + let inline delay x = Operators.delayM async x + let inline singleton x = Operators.returnM async x + let inline returnFrom x = Operators.returnFromM async x + let inline bindReturn ([] f) x = Operators.liftM async x f + let inline map ([] f) x = bindReturn f x + let inline mergeSources x y = Operators.zipM async async x y + let inline zip x y = mergeSources x y + let inline apply f x = Operators.applyM async async f x + + let inline flatten x = bind id x + +module Result = + open FsToolkit.ErrorHandling + + let inline either ([] okF) ([] errorF) = + function + | Ok x -> okF x + | Error e -> errorF e + + let inline bind ([] f) x = Operators.bindM result x f + let inline delay x = Operators.delayM result x + let inline singleton x = Operators.returnM result x + let inline returnFrom x = Operators.returnFromM result x + let inline bindReturn ([] f) x = Operators.bindReturnM result x f + let inline map ([] f) x = bindReturn f x + let inline mergeSources x y = Operators.mergeSourcesM result x y + let inline zip x y = mergeSources x y + + let inline apply f x = + mergeSources f x + |> bindReturn (fun (f', x') -> f' x') + + let inline sequence builder f x = + x + |> either + (fun x -> Operators.bindReturnM builder x f) + (fun x -> + x + |> Result.Error + |> Operators.returnM builder + ) + + let inline sequenceLift builder f x = + x + |> either + (fun x -> Operators.liftM builder x f) + (fun x -> + x + |> Result.Error + |> Operators.returnM builder + ) + + let inline sequenceAsync x = sequenceLift async Ok x + + let inline sequenceAsyncResult x = sequenceLift async id x + + let inline flatten x = bind id x + +module AsyncResult = + + type AsyncResultBuilder() = + member inline _.Return x = Async.singleton (Result.singleton x) + + member inline _.Bind(m, f: 'a -> Async>) = + m + |> Async.bind (fun x -> + Result.map f x + |> Result.sequenceAsyncResult + ) + + member inline _.Source(x: Async>) = x + + [] + module AsyncResultBuilderExt = + open System.Threading.Tasks + + type AsyncResultBuilder with + + member inline _.Source(x: Async<'a>) = Async.map Ok x + + member inline _.Source(x: Task<'a>) = + task { + let! x = x + return Ok x + } + |> Async.AwaitTask + + member inline _.Source(x: Result<_, _>) = Async.singleton x + + let asyncResult = AsyncResultBuilder() + + let inline bind ([] f) x = Operators.bindM asyncResult x f + let inline singleton x = Operators.returnM asyncResult x + + let example () = + asyncResult { + let! x = singleton 1 + let! y = singleton 2 + let! z = Async.singleton 3 + let! a = Result.singleton 4 + + return + x + + y + + z + + a + } + + + +module DisposableOptionThings = + open System + open System.Threading.Tasks + + [] + [] + [] + [] + type DisposableOption<'a when 'a :> IDisposable> = + | None + | Some of 'a + interface IDisposable with + member this.Dispose() = + match this with + | None -> () + | Some x -> x.Dispose() + + static member inline OfObj<'a when 'a :> IDisposable> (x: 'a) = + if box x |> isNull then None else Some x + + static member inline ToOption(x: DisposableOption<'a>) = + match x with + | None -> Option.None + | Some x -> Option.Some x + + static member inline ToValueOption(x: DisposableOption<'a>) = + match x with + | None -> ValueOption.None + | Some x -> ValueOption.Some x + + static member inline OfOption (x: 'a Option) = + match x with + | Option.None -> None + | Option.Some x -> Some x + + static member inline OfValueOption (x: 'a ValueOption) = + match x with + | ValueNone -> None + | ValueSome x -> Some x + + static member inline op_Implicit (x: 'a) = + DisposableOption.OfObj x + + static member inline op_Implicit (x: 'a DisposableOption) = + DisposableOption.ToOption x + + static member inline op_Implicit (x: 'a DisposableOption) = + DisposableOption.ToValueOption x + + static member inline op_Implicit (x: 'a Option) = + DisposableOption.OfOption x + + static member inline op_Imp licit (x: 'a ValueOption) = + DisposableOption.OfValueOption x + + + [] + module DisposableOption = + let inline bind f x = + match x with + | DisposableOption.Some x -> f x + | DisposableOption.None -> None + let inline map f x = + match x with + | DisposableOption.Some x -> Some (f x) + | DisposableOption.None -> None + let inline iter f x = + match x with + | DisposableOption.Some x -> f x + | DisposableOption.None -> () + + + [] + type AsyncDisposableOption<'a when 'a :> IAsyncDisposable> = + | Some of 'a + | None + interface IAsyncDisposable with + member this.DisposeAsync() = + match this with + | Some x -> x.DisposeAsync() + | None -> ValueTask() + + static member inline ofObj (x: 'a) = + if box x |> isNull then None else Some x + + member inline x.toOption() = + match x with + | Some x -> Option.Some x + | None -> Option.None + + member inline x.toValueOption() = + match x with + | Some x -> ValueOption.Some x + | None -> ValueOption.None + + static member inline ofOption (x: 'a Option) = + match x with + | Option.Some x -> Some x + | Option.None -> None + + static member inline ofValueOption (x: 'a ValueOption) = + match x with + | ValueOption.ValueSome x -> Some x + | ValueOption.ValueNone -> None + + static member inline op_Implicit (x: 'a) = + AsyncDisposableOption.ofObj x + + static member inline op_Implicit (x: 'a AsyncDisposableOption) = + x.toOption() + + static member inline op_Implicit (x: 'a AsyncDisposableOption) = + x.toValueOption() + + static member inline op_Implicit (x: 'a Option) = + AsyncDisposableOption.ofOption x + + static member inline op_Implicit (x: 'a ValueOption) = + AsyncDisposableOption.ofValueOption x + +module Examples = + open DisposableOptionThings + open System.Diagnostics + + let inline implicitConv (x: ^T) : ^U = ((^T or ^U) : (static member op_Implicit : ^T -> ^U) (x)) + let inline (!>) x = implicitConv x + let inline (|!>) x f = f (!> x) + + let activitySource = new ActivitySource("Playground.App") + + let example () = + use a = activitySource.StartActivity("lol") |> DisposableOption.OfObj + a |!> Option.iter(fun a -> a.AddTag("hello", "world") |> ignore) + () + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c4be768f..65508527 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,7 @@ FsToolkit.ErrorHandling is an extensive utility library based around the F# Result type, enabling consistent and powerful error handling. demystifyfp, TheAngryByrd - Copyright © 2018-23 + Copyright © 2018-24 https://demystifyfp.gitbook.io/fstoolkit-errorhandling MIT README.md diff --git a/src/FsToolkit.ErrorHandling.AsyncSeq/paket.references b/src/FsToolkit.ErrorHandling.AsyncSeq/paket.references index 1e2b033b..3df8daa9 100644 --- a/src/FsToolkit.ErrorHandling.AsyncSeq/paket.references +++ b/src/FsToolkit.ErrorHandling.AsyncSeq/paket.references @@ -1,6 +1,4 @@ Microsoft.SourceLink.GitHub - -group NetStandard2 - FSharp.Control.AsyncSeq -group NetStandard2_1 - FSharp.Control.AsyncSeq \ No newline at end of file +FSharp.Core +FSharp.Control.AsyncSeq +Microsoft.Bcl.AsyncInterfaces diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultBuilderBase.fs b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultBuilderBase.fs new file mode 100644 index 00000000..8e79edc1 --- /dev/null +++ b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultBuilderBase.fs @@ -0,0 +1,1379 @@ +namespace FsToolkit.ErrorHandling + + +/// Contains methods to build Tasks using the F# computation expression syntax +[] +module CancellableTaskResultBuilderBase = + open System + open System.Runtime.CompilerServices + open System.Threading + open System.Threading.Tasks + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.CompilerServices + open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Collections + open System.Collections.Generic + open IcedTasks + + + /// CancellationToken -> Task> + type CancellableTaskResult<'T, 'Error> = CancellableTask> + + + /// The extra data stored in ResumableStateMachine for tasks + [] + type CancellableTaskResultBuilderBaseStateMachineData<'T, 'Error, 'Builder> = + [] + val mutable CancellationToken: CancellationToken + + [] + val mutable Result: Result<'T, 'Error> + + [] + val mutable MethodBuilder: 'Builder + + member inline this.IsResultError = Result.isError this.Result + + /// Throws a if this token has had cancellation requested. + /// The token has had cancellation requested. + /// The associated has been disposed. + member inline this.ThrowIfCancellationRequested() = + this.CancellationToken.ThrowIfCancellationRequested() + + /// This is used by the compiler as a template for creating state machine structs + and CancellableTaskResultBuilderBaseStateMachine<'TOverall, 'Error, 'Builder> = + ResumableStateMachine> + + /// Represents the runtime continuation of a cancellableTasks state machine created dynamically + and CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, 'Builder> = + ResumptionFunc> + + /// Represents the runtime continuation of a cancellableTasks state machine created dynamically + and CancellableTaskResultBuilderBaseResumptionDynamicInfo<'TOverall, 'Error, 'Builder> = + ResumptionDynamicInfo> + + /// A special compiler-recognised delegate type for specifying blocks of cancellableTasks code with access to the state machine + and CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode, 'T> + + /// + /// Contains methods to build TaskLikes using the F# computation expression syntax + /// + type CancellableTaskResultBuilderBase() = + /// Creates a CancellableTasks that runs generator + /// The function to run + /// A CancellableTasks that runs generator + member inline _.Delay + ([] generator: + unit -> CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder>) + : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode.Delay(fun () -> generator ()) + + /// Creates A CancellableTasks that just returns (). + /// + /// The existence of this method permits the use of empty else branches in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// A CancellableTasks that returns (). + [] + member inline _.Zero + () + : CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder> = + ResumableCode.Zero() + + /// Creates A Computation that returns the result v. + /// + /// A cancellation check is performed when the computation is executed. + /// + /// The existence of this method permits the use of return in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// The value to return from the computation. + /// + /// A cancellableTasks that returns value when executed. + member inline _.Return + (value: 'T) + : CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, 'Builder> = + CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, 'Builder>(fun sm -> + sm.Data.Result <- Ok value + true + ) + + /// Creates a CancellableTasks that first runs task1 + /// and then runs computation2, returning the result of computation2. + /// + /// + /// + /// The existence of this method permits the use of expression sequencing in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// The first part of the sequenced computation. + /// The second part of the sequenced computation. + /// + /// A CancellableTasks that runs both of the computations sequentially. + member inline _.Combine + ( + task1: CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder>, + task2: CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode.Combine( + task1, + (CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder>(fun sm -> + if sm.Data.IsResultError then true else task2.Invoke(&sm) + )) + ) + + /// Creates A CancellableTasks that runs computation repeatedly + /// until guard() becomes false. + /// + /// + /// + /// The existence of this method permits the use of while in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// The function to determine when to stop executing computation. + /// The function to be executed. Equivalent to the body + /// of a while expression. + /// + /// A CancellableTasks that behaves similarly to a while loop when run. + member inline _.While + ( + guard: unit -> bool, + computation: CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder> = + let mutable keepGoing = true + + ResumableCode.While( + (fun () -> + keepGoing + && guard () + ), + CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder>(fun sm -> + if sm.Data.IsResultError then + keepGoing <- false + true + else + computation.Invoke(&sm) + ) + ) + + /// Creates A CancellableTasks that runs computation and returns its result. + /// If an exception happens then catchHandler(exn) is called and the resulting computation executed instead. + /// + /// + /// + /// The existence of this method permits the use of try/with in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// The input computation. + /// The function to run when computation throws an exception. + /// + /// A CancellableTasks that executes computation and calls catchHandler if an + /// exception is thrown. + member inline _.TryWith + ( + computation: CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder>, + catchHandler: + exn -> CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode.TryWith(computation, catchHandler) + + /// Creates A CancellableTasks that runs computation. The action compensation is executed + /// after computation completes, whether computation exits normally or by an exception. If compensation raises an exception itself + /// the original exception is discarded and the new exception becomes the overall result of the computation. + /// + /// + /// + /// The existence of this method permits the use of try/finally in the + /// cancellableTasks { ... } computation expression syntax. + /// + /// The input computation. + /// The action to be run after computation completes or raises an + /// exception (including cancellation). + /// + /// A CancellableTasks that executes computation and compensation afterwards or + /// when an exception is raised. + member inline _.TryFinally + ( + computation: CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder>, + compensation: unit -> unit + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode.TryFinally( + computation, + ResumableCode<_, _>(fun _ -> + compensation () + true + ) + ) + + + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// + [] + static member inline BindDynamic + ( + sm: + byref>>, + [] getAwaiter: CancellationToken -> 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : bool = + sm.Data.ThrowIfCancellationRequested() + + let mutable awaiter = getAwaiter sm.Data.CancellationToken + + let cont = + (CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, _>(fun sm -> + let result = Awaiter.GetResult awaiter + + match result with + | Ok result -> (continuation result).Invoke(&sm) + | Error e -> + sm.Data.Result <- Error e + true + )) + + // shortcut to continue immediately + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + + /// Creates A CancellableTask that runs computation, and when + /// computation generates a result T, runs binder res. + /// + /// A cancellation check is performed when the computation is executed. + /// + /// The existence of this method permits the use of let! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The computation to provide an unbound result. + /// The function to bind the result of computation. + /// + /// A CancellableTask that performs a monadic bind on the result + /// of computation. + [] + member inline _.Bind + ( + [] getAwaiterTResult: CancellationToken -> 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder> = + + CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>(fun sm -> + if __useResumableCode then + //-- RESUMABLE CODE START + sm.Data.ThrowIfCancellationRequested() + // Get an awaiter from the Awaiter + let mutable awaiter = getAwaiterTResult sm.Data.CancellationToken + + let mutable __stack_fin = true + + if not (Awaiter.IsCompleted awaiter) then + // This will yield with __stack_yield_fin = false + // This will resume with __stack_yield_fin = true + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_fin <- __stack_yield_fin + + if __stack_fin then + let result = Awaiter.GetResult awaiter + + match result with + | Ok result -> (continuation result).Invoke(&sm) + | Error e -> + sm.Data.Result <- Error e + true + else + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted(&sm.Data.MethodBuilder, &awaiter, &sm) + + false + else + CancellableTaskResultBuilderBase.BindDynamic( + &sm, + getAwaiterTResult, + continuation + ) + //-- RESUMABLE CODE END + ) + + + /// Creates a CancellableTask that enumerates the sequence seq + /// on demand and runs body for each element. + /// + /// A cancellation check is performed on each iteration of the loop. + /// + /// The existence of this method permits the use of for in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The sequence to enumerate. + /// A function to take an item from the sequence and create + /// A CancellableTask. Can be seen as the body of the for expression. + /// + /// A CancellableTask that will enumerate the sequence and run body + /// for each element. + member inline this.For + ( + sequence: seq<'T>, + body: 'T -> CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder> = + ResumableCode.Using( + sequence.GetEnumerator(), + // ... and its body is a while loop that advances the enumerator and runs the body on each element. + (fun e -> + this.While( + (fun () -> e.MoveNext()), + CancellableTaskResultBuilderBaseCode<'TOverall, unit, 'Error, 'Builder>(fun + sm -> + (body e.Current).Invoke(&sm) + ) + ) + ) + ) + + /// Creates A CancellableTask that runs computation. The action compensation is executed + /// after computation completes, whether computation exits normally or by an exception. If compensation raises an exception itself + /// the original exception is discarded and the new exception becomes the overall result of the computation. + /// + /// + /// + /// The existence of this method permits the use of try/finally in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The input computation. + /// The action to be run after computation completes or raises an + /// exception. + /// + /// A CancellableTask that executes computation and compensation afterwards or + /// when an exception is raised. + member inline internal this.TryFinallyAsync + ( + computation: CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder>, + compensation: unit -> 'Awaitable + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + ResumableCode.TryFinallyAsync( + computation, + ResumableCode<_, _>(fun sm -> + + if __useResumableCode then + let mutable __stack_condition_fin = true + let mutable awaiter = compensation () + + if not (Awaiter.IsCompleted awaiter) then + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_condition_fin <- __stack_yield_fin + + if __stack_condition_fin then + Awaiter.GetResult awaiter + else + + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) + + __stack_condition_fin + else + let mutable awaiter = compensation () + + let cont = + CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, 'Builder>(fun + sm -> + Awaiter.GetResult awaiter + true + ) + + // shortcut to continue immediately + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- + (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + ) + ) + + /// Creates A CancellableTask that runs binder(resource). + /// The action resource.DisposeAsync() is executed as this computation yields its result + /// or if the CancellableTask exits by an exception or by cancellation. + /// + /// + /// + /// The existence of this method permits the use of use and use! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The resource to be used and disposed. + /// The function that takes the resource and returns an asynchronous + /// computation. + /// + /// A CancellableTask that binds and eventually disposes resource. + /// + member inline this.Using + ( + resource: #IAsyncDisposable, + binder: + #IAsyncDisposable + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> = + this.TryFinallyAsync( + (fun sm -> (binder resource).Invoke(&sm)), + (fun () -> + if not (isNull (box resource)) then + resource.DisposeAsync() + |> Awaitable.GetAwaiter + else + ValueTask() + |> Awaitable.GetAwaiter + ) + ) + + + member inline internal _.WhileAsync + ( + [] condition, + body: CancellableTaskResultBuilderBaseCode<_, unit, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<_, unit, 'Error, 'Builder> = + let mutable condition_res = true + + ResumableCode.While( + (fun () -> condition_res), + CancellableTaskResultBuilderBaseCode<_, unit, 'Error, 'Builder>(fun sm -> + if __useResumableCode then + + let mutable __stack_condition_fin = true + let mutable awaiter = condition () + + if Awaiter.IsCompleted awaiter then + + __stack_condition_fin <- true + + condition_res <- Awaiter.GetResult awaiter + else + + // This will yield with __stack_fin = false + // This will resume with __stack_fin = true + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_condition_fin <- __stack_yield_fin + + if __stack_condition_fin then + condition_res <- Awaiter.GetResult awaiter + + + if __stack_condition_fin then + + if condition_res then body.Invoke(&sm) else true + else + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) + + false + else + + let mutable awaiter = condition () + + let cont = + CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, 'Builder>(fun + sm -> + condition_res <- Awaiter.GetResult awaiter + if condition_res then body.Invoke(&sm) else true + ) + + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- + (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + ) + ) + + member inline this.For + ( + source: #IAsyncEnumerable<'T>, + body: 'T -> CancellableTaskResultBuilderBaseCode<_, unit, 'Error, 'Builder> + ) : CancellableTaskResultBuilderBaseCode<_, _, 'Error, 'Builder> = + + CancellableTaskResultBuilderBaseCode<_, _, 'Error, 'Builder>(fun sm -> + this + .Using( + source.GetAsyncEnumerator sm.Data.CancellationToken, + (fun (e: IAsyncEnumerator<'T>) -> + this.WhileAsync( + (fun () -> Awaitable.GetAwaiter(e.MoveNextAsync())), + (fun sm -> (body e.Current).Invoke(&sm)) + ) + ) + + ) + .Invoke(&sm) + ) + + + /// + [] + module LowPriority2 = + // Low priority extensions + type CancellableTaskResultBuilderBase with + + + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// + [] + static member inline BindDynamic + ( + sm: + byref>>, + [] getAwaiter: CancellationToken -> 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : bool = + sm.Data.ThrowIfCancellationRequested() + + let mutable awaiter = getAwaiter sm.Data.CancellationToken + + let cont = + (CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, _>(fun sm -> + let result = Awaiter.GetResult awaiter + + (continuation result).Invoke(&sm) + )) + + // shortcut to continue immediately + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- + (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + + /// Creates A CancellableTask that runs computation, and when + /// computation generates a result T, runs binder res. + /// + /// A cancellation check is performed when the computation is executed. + /// + /// The existence of this method permits the use of let! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The computation to provide an unbound result. + /// The function to bind the result of computation. + /// + /// A CancellableTask that performs a monadic bind on the result + /// of computation. + [] + member inline _.Bind + ( + [] getAwaiterT: CancellationToken -> 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder> = + + CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>(fun sm -> + if __useResumableCode then + //-- RESUMABLE CODE START + sm.Data.ThrowIfCancellationRequested() + // Get an awaiter from the Awaiter + let mutable awaiter = getAwaiterT sm.Data.CancellationToken + + let mutable __stack_fin = true + + if not (Awaiter.IsCompleted awaiter) then + // This will yield with __stack_yield_fin = false + // This will resume with __stack_yield_fin = true + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_fin <- __stack_yield_fin + + if __stack_fin then + let result = Awaiter.GetResult awaiter + + (continuation result).Invoke(&sm) + else + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) + + false + else + CancellableTaskResultBuilderBase.BindDynamic( + &sm, + getAwaiterT, + continuation + ) + //-- RESUMABLE CODE END + ) + + + /// Delegates to the input computation. + /// + /// The existence of this method permits the use of return! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The input computation. + /// + /// The input computation. + [] + member inline this.ReturnFrom + ([] getAwaiterT: CancellationToken -> 'Awaiter) + = + this.Bind( + getAwaiterT = (fun ct -> getAwaiterT ct), + continuation = (fun v -> this.Return v) + ) + + + // [] + // member inline this.BindReturn + // ( + // [] getAwaiterT: CancellationToken -> 'Awaiter, + // mapper: 'TResult1 -> 'TResult2 + // ) : CancellableTaskResultBuilderBaseCode<_, _, _, _> = + // this.Bind((fun ct -> getAwaiterT ct), (fun v -> this.Return(mapper v))) + + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// + [] + static member inline BindDynamic + ( + sm: + byref>>, + awaiter: 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : bool = + sm.Data.ThrowIfCancellationRequested() + let mutable awaiter = awaiter + + let cont = + (CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, 'Builder>(fun + sm -> + let result = Awaiter.GetResult awaiter + + (continuation result).Invoke(&sm) + )) + + // shortcut to continue immediately + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- + (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + + /// Creates A CancellableTask that runs computation, and when + /// computation generates a result T, runs binder res. + /// + /// A cancellation check is performed when the computation is executed. + /// + /// The existence of this method permits the use of let! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The computation to provide an unbound result. + /// The function to bind the result of computation. + /// + /// A CancellableTask that performs a monadic bind on the result + /// of computation. + [] + member inline _.Bind + ( + awaiterT: 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder> = + + CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>(fun sm -> + if __useResumableCode then + //-- RESUMABLE CODE START + sm.Data.ThrowIfCancellationRequested() + // Get an awaiter from the Awaiter + let mutable awaiter = awaiterT + + let mutable __stack_fin = true + + if not (Awaiter.IsCompleted awaiter) then + // This will yield with __stack_yield_fin = false + // This will resume with __stack_yield_fin = true + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_fin <- __stack_yield_fin + + if __stack_fin then + let result = Awaiter.GetResult awaiter + + (continuation result).Invoke(&sm) + else + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) + + false + else + CancellableTaskResultBuilderBase.BindDynamic(&sm, awaiterT, continuation) + //-- RESUMABLE CODE END + ) + + /// Delegates to the input computation. + /// + /// The existence of this method permits the use of return! in the + /// task { ... } computation expression syntax. + /// + /// The input computation. + /// + /// The input computation. + [] + member inline this.ReturnFrom + (awaiterT: 'Awaiter) + : CancellableTaskResultBuilderBaseCode<_, _, _, 'Builder> = + this.Bind(awaiterT = awaiterT, continuation = (fun v -> this.Return v)) + + // [] + // member inline this.BindReturn + // ( + // awaiterT: 'Awaiter, + // [] mapper: 'a -> 'TResult2 + // ) : CancellableTaskResultBuilderBaseCode<'TResult2, 'TResult2, 'Error, 'Builder> = + // this.Bind(awaiterT = awaiterT, continuation = (fun v -> this.Return(mapper v))) + + + /// + [] + module LowPriority = + // Low priority extensions + type CancellableTaskResultBuilderBase with + + // /// + // /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + // /// + // [] + // static member inline BindDynamic + // ( + // sm: + // byref>>, + // [] getAwaiter: CancellationToken -> 'Awaiter, + // continuation: + // ('TResult1 + // -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + // ) : bool = + // sm.Data.ThrowIfCancellationRequested() + + // let mutable awaiter = getAwaiter sm.Data.CancellationToken + + // let cont = + // (CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, _>(fun sm -> + // let result = Awaiter.GetResult awaiter + + // match result with + // | Ok result -> (continuation result).Invoke(&sm) + // | Error e -> + // sm.Data.Result <- Error e + // true + // )) + + // // shortcut to continue immediately + // if Awaiter.IsCompleted awaiter then + // cont.Invoke(&sm) + // else + // sm.ResumptionDynamicInfo.ResumptionData <- + // (awaiter :> ICriticalNotifyCompletion) + + // sm.ResumptionDynamicInfo.ResumptionFunc <- cont + // false + + // /// Creates A CancellableTask that runs computation, and when + // /// computation generates a result T, runs binder res. + // /// + // /// A cancellation check is performed when the computation is executed. + // /// + // /// The existence of this method permits the use of let! in the + // /// cancellableTask { ... } computation expression syntax. + // /// + // /// The computation to provide an unbound result. + // /// The function to bind the result of computation. + // /// + // /// A CancellableTask that performs a monadic bind on the result + // /// of computation. + // [] + // member inline _.Bind + // ( + // [] getAwaiterTResult: CancellationToken -> 'Awaiter, + // continuation: + // ('TResult1 + // -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + // ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder> = + + // CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>(fun sm -> + // if __useResumableCode then + // //-- RESUMABLE CODE START + // sm.Data.ThrowIfCancellationRequested() + // // Get an awaiter from the Awaiter + // let mutable awaiter = getAwaiterTResult sm.Data.CancellationToken + + // let mutable __stack_fin = true + + // if not (Awaiter.IsCompleted awaiter) then + // // This will yield with __stack_yield_fin = false + // // This will resume with __stack_yield_fin = true + // let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + // __stack_fin <- __stack_yield_fin + + // if __stack_fin then + // let result = Awaiter.GetResult awaiter + + // match result with + // | Ok result -> (continuation result).Invoke(&sm) + // | Error e -> + // sm.Data.Result <- Error e + // true + // else + // let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + // MethodBuilder.AwaitUnsafeOnCompleted( + // &sm.Data.MethodBuilder, + // &awaiter, + // &sm + // ) + + // false + // else + // CancellableTaskResultBuilderBase.BindDynamic( + // &sm, + // getAwaiterTResult, + // continuation + // ) + // //-- RESUMABLE CODE END + // ) + + + /// Delegates to the input computation. + /// + /// The existence of this method permits the use of return! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The input computation. + /// + /// The input computation. + [] + member inline this.ReturnFrom + ([] getAwaiterTResult: CancellationToken -> 'Awaiter) + = + this.Bind( + getAwaiterTResult = (fun ct -> getAwaiterTResult ct), + continuation = (fun v -> this.Return v) + ) + + + // [] + // member inline this.BindReturn + // ( + // [] getAwaiterTResult: CancellationToken -> 'Awaiter, + // mapper: 'TResult1 -> 'TResult2 + // ) : CancellableTaskResultBuilderBaseCode<_, _, _, _> = + // this.Bind((fun ct -> getAwaiterTResult ct), (fun v -> this.Return(mapper v))) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a CancellationToken -> 'Awaitable into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + [] + member inline _.Source<'Awaitable, 'TResult1, 'Awaiter, 'TOverall + when Awaitable<'Awaitable, 'Awaiter, 'TResult1>> + ([] cancellableAwaiter: CancellationToken -> 'Awaiter) + : CancellationToken -> 'Awaiter = + (fun ct -> cancellableAwaiter ct) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a CancellationToken -> 'Awaitable into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + [] + member inline _.Source<'Awaitable, 'TResult1, 'Awaiter, 'TOverall + when Awaitable<'Awaitable, 'Awaiter, 'TResult1>> + ([] cancellableAwaitable: CancellationToken -> 'Awaitable) + : CancellationToken -> 'Awaiter = + (fun ct -> Awaitable.GetAwaiter(cancellableAwaitable ct)) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a unit -> 'Awaitable into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + [] + member inline _.Source<'Awaitable, 'TResult1, 'Awaiter, 'TOverall + when Awaitable<'Awaitable, 'Awaiter, 'TResult1>> + ([] coldAwaitable: unit -> 'Awaitable) + : CancellationToken -> 'Awaiter = + (fun ct -> Awaitable.GetAwaiter(coldAwaitable ())) + + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// + [] + static member inline BindDynamic + ( + sm: + byref>>, + awaiter: 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : bool = + sm.Data.ThrowIfCancellationRequested() + let mutable awaiter = awaiter + + let cont = + (CancellableTaskResultBuilderBaseResumptionFunc<'TOverall, 'Error, 'Builder>(fun + sm -> + let result = Awaiter.GetResult awaiter + + match result with + | Ok result -> (continuation result).Invoke(&sm) + | Error e -> + sm.Data.Result <- Error e + true + )) + + // shortcut to continue immediately + if Awaiter.IsCompleted awaiter then + cont.Invoke(&sm) + else + sm.ResumptionDynamicInfo.ResumptionData <- + (awaiter :> ICriticalNotifyCompletion) + + sm.ResumptionDynamicInfo.ResumptionFunc <- cont + false + + /// Creates A CancellableTask that runs computation, and when + /// computation generates a result T, runs binder res. + /// + /// A cancellation check is performed when the computation is executed. + /// + /// The existence of this method permits the use of let! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The computation to provide an unbound result. + /// The function to bind the result of computation. + /// + /// A CancellableTask that performs a monadic bind on the result + /// of computation. + [] + member inline _.Bind + ( + awaiterTResult: 'Awaiter, + continuation: + ('TResult1 + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>) + ) : CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder> = + + CancellableTaskResultBuilderBaseCode<'TOverall, 'TResult2, 'Error, 'Builder>(fun sm -> + if __useResumableCode then + //-- RESUMABLE CODE START + sm.Data.ThrowIfCancellationRequested() + // Get an awaiter from the Awaiter + let mutable awaiter = awaiterTResult + + let mutable __stack_fin = true + + if not (Awaiter.IsCompleted awaiter) then + // This will yield with __stack_yield_fin = false + // This will resume with __stack_yield_fin = true + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_fin <- __stack_yield_fin + + if __stack_fin then + let result = Awaiter.GetResult awaiter + + match result with + | Ok result -> (continuation result).Invoke(&sm) + | Error e -> + sm.Data.Result <- Error e + true + else + let mutable awaiter = awaiter :> ICriticalNotifyCompletion + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) + + false + else + CancellableTaskResultBuilderBase.BindDynamic( + &sm, + awaiterTResult, + continuation + ) + //-- RESUMABLE CODE END + ) + + /// Delegates to the input computation. + /// + /// The existence of this method permits the use of return! in the + /// task { ... } computation expression syntax. + /// + /// The input computation. + /// + /// The input computation. + [] + member inline this.ReturnFrom + (awaiterTResult: 'Awaiter) + : CancellableTaskResultBuilderBaseCode<_, _, _, 'Builder> = + this.Bind(awaiterTResult = awaiterTResult, continuation = (fun v -> this.Return v)) + + // [] + // member inline this.BindReturn + // ( + // awaiterTResult: 'Awaiter, + // [] mapper: 'a -> 'TResult2 + // ) : CancellableTaskResultBuilderBaseCode<'TResult2, 'TResult2, 'Error, 'Builder> = + // this.Bind( + // awaiterTResult = awaiterTResult, + // continuation = (fun v -> this.Return(mapper v)) + // ) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This is the identify function. + /// + /// 'Awaiter + [] + member inline _.Source<'TResult1, 'TResult2, 'Awaiter, 'TOverall + when Awaiter<'Awaiter, 'TResult1>> + (awaiter: 'Awaiter) + : 'Awaiter = + awaiter + + + /// Allows the computation expression to turn other types into 'Awaiter + /// + /// This turns a ^Awaitable into a 'Awaiter. + /// + /// 'Awaiter + [] + member inline _.Source<'Awaitable, 'TResult1, 'TResult2, 'Awaiter, 'TOverall + when Awaitable<'Awaitable, 'Awaiter, 'TResult1>> + (task: 'Awaitable) + : 'Awaiter = + Awaitable.GetAwaiter task + + + /// Creates A CancellableTask that runs binder(resource). + /// The action resource.Dispose() is executed as this computation yields its result + /// or if the CancellableTask exits by an exception or by cancellation. + /// + /// + /// + /// The existence of this method permits the use of use and use! in the + /// cancellableTask { ... } computation expression syntax. + /// + /// The resource to be used and disposed. + /// The function that takes the resource and returns an asynchronous + /// computation. + /// + /// A CancellableTask that binds and eventually disposes resource. + /// + member inline _.Using + ( + resource: #IDisposable, + binder: + #IDisposable + -> CancellableTaskResultBuilderBaseCode<'TOverall, 'T, 'Error, 'Builder> + ) = + ResumableCode.Using(resource, binder) + + + /// Allows the computation expression to turn other types into other types + /// + /// This is the identify function for For binds. + /// + /// IEnumerable + member inline _.Source(s: #seq<_>) : #seq<_> = s + + + [] + module MedHighPriority = + + type CancellableTaskResultBuilderBase with + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a Task<'T> into a CancellationToken -> 'Awaiter. + /// + /// 'Awaiter + member inline _.Source(taskAwaiter: TaskAwaiter<'T>) : Awaiter, 'T> = + taskAwaiter + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a Task<'T> into a CancellationToken -> 'Awaiter. + /// + /// 'Awaiter + member inline _.Source(taskT: Task<'T>) : Awaiter, 'T> = + Awaitable.GetTaskAwaiter taskT + + + member inline _.Source + (cancellableTask: CancellationToken -> Task<_>) + : CancellationToken -> Awaiter, _> = + fun ct -> Awaitable.GetTaskAwaiter(cancellableTask ct) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a Async<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline this.Source(computation: Async<'T>) = + this.Source(Async.AsCancellableTask(computation)) + + + /// + [] + module HighPriority = + + + type Microsoft.FSharp.Control.Async with + + static member inline AwaitCancellableTaskResult + ([] t: CancellableTaskResult<'T, 'Error>) + = + async { + let! ct = Async.CancellationToken + + return! + t ct + |> Async.AwaitTask + } + + static member inline AsCancellableTaskResult(computation: Async<'T>) = + fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) + + type AsyncEx with + + static member inline AwaitCancellableTaskResult + ([] t: CancellableTaskResult<'T, 'Error>) + = + async { + let! ct = Async.CancellationToken + + return! + t ct + |> Async.AwaitTask + } + + static member inline AsCancellableTaskResult(computation: Async<'T>) = + fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) + + + type AsyncResultCE.AsyncResultBuilder with + + member inline this.Source + ([] t: CancellableTaskResult<'T, 'Error>) + : Async<_> = + Async.AwaitCancellableTaskResult t + + + // type AsyncEx with + + // /// Return an asynchronous computation that will wait for the given task to complete and return + // /// its result. + // /// + // /// + // /// This is based on Async.Await overload (esp. AwaitTask without throwing AggregateException) + // /// + // static member inline AwaitCancellableTask + // ([] t: CancellationToken -> Task<'T>) + // = + // asyncEx { + // let! ct = Async.CancellationToken + // return! t ct + // } + + // /// Return an asynchronous computation that will wait for the given task to complete and return + // /// its result. + // /// + // /// + // /// This is based on Async.Await overload (esp. AwaitTask without throwing AggregateException) + // /// + // static member inline AwaitCancellableTask + // ([] t: CancellationToken -> Task) + // = + // asyncEx { + // let! ct = Async.CancellationToken + // return! t ct + // } + + // type Microsoft.FSharp.Control.Async with + + // /// Return an asynchronous computation that will wait for the given task to complete and return + // /// its result. + // static member inline AwaitCancellableTask + // ([] t: CancellationToken -> Task<'T>) + // = + // async { + // let! ct = Async.CancellationToken + + // return! + // t ct + // |> Async.AwaitTask + // } + + // /// Return an asynchronous computation that will wait for the given task to complete and return + // /// its result. + // static member inline AwaitCancellableTask + // ([] t: CancellationToken -> Task) + // = + // async { + // let! ct = Async.CancellationToken + + // return! + // t ct + // |> Async.AwaitTask + // } + + // /// Runs an asynchronous computation, starting on the current operating system thread. + // static member inline AsCancellableTask + // (computation: Async<'T>) + // : CancellationToken -> Task<_> = + // fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) + + // High priority extensions + type CancellableTaskResultBuilderBase with + + /// Allows the computation expression to turn other types into other types + /// + /// This is the identify function for For binds. + /// + /// IEnumerable + member inline _.Source(s: #IAsyncEnumerable<_>) = s + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline _.Source + ([] task: unit -> TaskAwaiter<'T>) + : CancellationToken -> Awaiter, 'T> = + (fun (ct: CancellationToken) -> (task ())) + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline _.Source + ([] task: unit -> Task<'T>) + : CancellationToken -> Awaiter, 'T> = + (fun (ct: CancellationToken) -> Awaitable.GetTaskAwaiter(task ())) + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a CancellableTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline _.Source + ([] cancellableTaskAwaiter: CancellationToken -> TaskAwaiter<'T>) + : CancellationToken -> Awaiter, 'T> = + (fun ct -> (cancellableTaskAwaiter ct)) + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a CancellableTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline _.Source + ([] task: CancellationToken -> Task<'T>) + : CancellationToken -> Awaiter, 'T> = + (fun ct -> Awaitable.GetTaskAwaiter(task ct)) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline _.Source(taskResult: TaskResult<'T, 'Error>) = + Awaitable.GetTaskAwaiter(taskResult) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline this.Source + (asyncResult: Async>) + : CancellationToken -> TaskAwaiter> = + this.Source(Async.AsCancellableTask asyncResult) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline this.Source + (asyncChoice: Async>) + : CancellationToken -> TaskAwaiter> = + this.Source(Async.map Result.ofChoice asyncChoice) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline this.Source(result: Result<'T, 'Error>) = + this.Source(ValueTask<_>(result)) + + + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter + /// + /// This turns a ColdTask<'T> into a CancellationToken -> 'Awaiter. + /// + /// CancellationToken -> 'Awaiter + member inline this.Source(choice: Choice<'T, 'Error>) = + this.Source(ValueTask<_>(Result.ofChoice choice)) diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs index c8648c2e..47b92aa5 100644 --- a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs +++ b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskResultCE.fs @@ -1,6 +1,6 @@ namespace FsToolkit.ErrorHandling - +/// Contains methods to build CancellableTasks using the F# computation expression syntax [] module CancellableTaskResultCE = @@ -13,262 +13,10 @@ module CancellableTaskResultCE = open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators open Microsoft.FSharp.Collections - open FsToolkit.ErrorHandling open IcedTasks - /// CancellationToken -> Task> - type CancellableTaskResult<'T, 'Error> = CancellableTask> - - - /// The extra data stored in ResumableStateMachine for tasks - [] - type CancellableTaskResultStateMachineData<'T, 'Error> = - [] - val mutable CancellationToken: CancellationToken - - [] - val mutable Result: Result<'T, 'Error> - - [] - val mutable MethodBuilder: CancellableTaskResultMethodBuilder<'T, 'Error> - - - member inline this.IsResultError = Result.isError this.Result - member inline this.IsTaskCompleted = this.MethodBuilder.Task.IsCompleted - - member inline this.ThrowIfCancellationRequested() = - this.CancellationToken.ThrowIfCancellationRequested() - - and CancellableTaskResultMethodBuilder<'TOverall, 'Error> = - AsyncTaskMethodBuilder> - - and CancellableTaskResultStateMachine<'TOverall, 'Error> = - ResumableStateMachine> - - and CancellableTaskResultResumptionFunc<'TOverall, 'Error> = - ResumptionFunc> - - and CancellableTaskResultResumptionDynamicInfo<'TOverall, 'Error> = - ResumptionDynamicInfo> - - and CancellableTaskResultCode<'TOverall, 'Error, 'T> = - ResumableCode, 'T> - - type CancellableTaskResultBuilderBase() = - - member inline _.Delay - (generator: unit -> CancellableTaskResultCode<'TOverall, 'Error, 'T>) - : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - CancellableTaskResultCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (generator ()).Invoke(&sm) - ) - - /// Used to represent no-ops like the implicit empty "else" branch of an "if" expression. - [] - member inline _.Zero<'TOverall, 'Error> - () - : CancellableTaskResultCode<'TOverall, 'Error, unit> = - ResumableCode.Zero() - - member inline _.Return(value: 'T) : CancellableTaskResultCode<'T, 'Error, 'T> = - CancellableTaskResultCode<'T, _, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - sm.Data.Result <- Ok value - true - ) - - - /// Chains together a step with its following step. - /// Note that this requires that the first step has no result. - /// This prevents constructs like `task { return 1; return 2; }`. - member inline _.Combine - ( - task1: CancellableTaskResultCode<'TOverall, 'Error, unit>, - task2: CancellableTaskResultCode<'TOverall, 'Error, 'T> - ) : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - ResumableCode.Combine( - CancellableTaskResultCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - task1.Invoke(&sm) - ), - CancellableTaskResultCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - if sm.Data.IsResultError then true else task2.Invoke(&sm) - ) - ) - - - /// Builds a step that executes the body while the condition predicate is true. - member inline _.While - ( - [] condition: unit -> bool, - body: CancellableTaskResultCode<'TOverall, 'Error, unit> - ) : CancellableTaskResultCode<'TOverall, 'Error, unit> = - let mutable keepGoing = true - - ResumableCode.While( - (fun () -> - keepGoing - && condition () - ), - CancellableTaskResultCode<_, _, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - - if sm.Data.IsResultError then - keepGoing <- false - sm.Data.MethodBuilder.SetResult sm.Data.Result - true - else - body.Invoke(&sm) - ) - ) - - /// Wraps a step in a try/with. This catches exceptions both in the evaluation of the function - /// to retrieve the step, and in the continuation of the step (if any). - member inline _.TryWith - ( - computation: CancellableTaskResultCode<'TOverall, 'Error, 'T>, - catchHandler: exn -> CancellableTaskResultCode<'TOverall, 'Error, 'T> - ) : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - ResumableCode.TryWith( - CancellableTaskResultCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - computation.Invoke(&sm) - ), - catchHandler - ) - - /// Wraps a step in a try/finally. This catches exceptions both in the evaluation of the function - /// to retrieve the step, and in the continuation of the step (if any). - member inline _.TryFinally - ( - computation: CancellableTaskResultCode<'TOverall, 'Error, 'T>, - [] compensation: unit -> unit - ) : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - ResumableCode.TryFinally( - - CancellableTaskResultCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - computation.Invoke(&sm) - ), - ResumableCode<_, _>(fun _ -> - compensation () - true - ) - ) - - member inline this.For - ( - sequence: seq<'T>, - body: 'T -> CancellableTaskResultCode<'TOverall, 'Error, unit> - ) : CancellableTaskResultCode<'TOverall, 'Error, unit> = - ResumableCode.Using( - sequence.GetEnumerator(), - // ... and its body is a while loop that advances the enumerator and runs the body on each element. - (fun e -> - this.While( - (fun () -> e.MoveNext()), - CancellableTaskResultCode<'TOverall, 'Error, unit>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (body e.Current).Invoke(&sm) - ) - ) - ) - ) - - member inline internal this.TryFinallyAsync - ( - body: CancellableTaskResultCode<'TOverall, 'Error, 'T>, - compensation: unit -> ValueTask - ) : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - ResumableCode.TryFinallyAsync( - body, - ResumableCode<_, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - - if __useResumableCode then - let mutable __stack_condition_fin = true - let __stack_vtask = compensation () - - if not __stack_vtask.IsCompleted then - let mutable awaiter = __stack_vtask.GetAwaiter() - let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) - __stack_condition_fin <- __stack_yield_fin - - if not __stack_condition_fin then - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) - - __stack_condition_fin - else - let vtask = compensation () - let mutable awaiter = vtask.GetAwaiter() - - let cont = - CancellableTaskResultResumptionFunc<'TOverall, 'Error>(fun sm -> - awaiter.GetResult() - |> ignore - - true - ) - - // shortcut to continue immediately - if awaiter.IsCompleted then - true - else - sm.ResumptionDynamicInfo.ResumptionData <- - (awaiter :> ICriticalNotifyCompletion) - - sm.ResumptionDynamicInfo.ResumptionFunc <- cont - false - ) - ) - - member inline this.Using<'Resource, 'TOverall, 'Error, 'T when 'Resource :> IAsyncDisposable> - ( - resource: 'Resource, - body: 'Resource -> CancellableTaskResultCode<'TOverall, 'Error, 'T> - ) : CancellableTaskResultCode<'TOverall, 'Error, 'T> = - this.TryFinallyAsync( - (fun sm -> (body resource).Invoke(&sm)), - (fun () -> - if not (isNull (box resource)) then - resource.DisposeAsync() - else - ValueTask() - ) - ) - - member inline this.Source - (ctr: CancellableTaskResult<'T, 'Error>) - : CancellableTaskResult<'T, 'Error> = - ctr - - member inline this.Source(xs: #seq<_>) = xs - - member inline _.Source(result: TaskResult<_, _>) : CancellableTaskResult<_, _> = - cancellableTask { return! result } - - member inline _.Source(result: Async>) : CancellableTaskResult<_, _> = - cancellableTask { return! result } - - member inline this.Source(result: Async>) : CancellableTaskResult<_, _> = - result - |> Async.map Result.ofChoice - |> this.Source - - member inline _.Source(t: ValueTask>) : CancellableTaskResult<'T, 'Error> = - cancellableTask { return! t } - - member inline _.Source(result: Result<_, _>) : CancellableTaskResult<_, _> = - CancellableTask.singleton result - - member inline this.Source(result: Choice<_, _>) : CancellableTaskResult<_, _> = - result - |> Result.ofChoice - |> this.Source - + /// Contains methods to build CancellableTasks using the F# computation expression syntax type CancellableTaskResultBuilder() = inherit CancellableTaskResultBuilderBase() @@ -279,17 +27,22 @@ module CancellableTaskResultCE = // The executor stays constant throughout the execution, it wraps each step // of the execution in a try/with. The resumption is changed at each step // to represent the continuation of the computation. + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// static member inline RunDynamic - (code: CancellableTaskResultCode<'T, 'Error, 'T>) + (code: CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, _>) : CancellableTaskResult<'T, 'Error> = - let mutable sm = CancellableTaskResultStateMachine<'T, 'Error>() + let mutable sm = CancellableTaskResultBuilderBaseStateMachine<'T, 'Error, _>() let initialResumptionFunc = - CancellableTaskResultResumptionFunc<'T, 'Error>(fun sm -> code.Invoke(&sm)) + CancellableTaskResultBuilderBaseResumptionFunc<'T, 'Error, _>(fun sm -> + code.Invoke(&sm) + ) let resumptionInfo = - { new CancellableTaskResultResumptionDynamicInfo<'T, 'Error>(initialResumptionFunc) with + { new CancellableTaskResultBuilderBaseResumptionDynamicInfo<'T, 'Error, _>(initialResumptionFunc) with member info.MoveNext(sm) = let mutable savedExn = null @@ -297,29 +50,30 @@ module CancellableTaskResultCE = sm.ResumptionDynamicInfo.ResumptionData <- null let step = info.ResumptionFunc.Invoke(&sm) - if sm.Data.IsTaskCompleted then - () - elif step then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) + if step then + MethodBuilder.SetResult(&sm.Data.MethodBuilder, sm.Data.Result) else let mutable awaiter = sm.ResumptionDynamicInfo.ResumptionData :?> ICriticalNotifyCompletion assert not (isNull awaiter) - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) + + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) with exn -> savedExn <- exn // Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567 match savedExn with | null -> () - | exn -> - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn + | exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn) member _.SetStateMachine(sm, state) = - sm.Data.MethodBuilder.SetStateMachine(state) + MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state) } fun (ct) -> @@ -328,17 +82,17 @@ module CancellableTaskResultCE = else sm.Data.CancellationToken <- ct sm.ResumptionDynamicInfo <- resumptionInfo - - sm.Data.MethodBuilder <- CancellableTaskResultMethodBuilder<'T, 'Error>.Create() - + sm.Data.MethodBuilder <- AsyncTaskMethodBuilder>.Create() sm.Data.MethodBuilder.Start(&sm) sm.Data.MethodBuilder.Task + + /// Hosts the task code in a state machine and starts the task. member inline _.Run - (code: CancellableTaskResultCode<'T, 'Error, 'T>) + (code: CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, _>) : CancellableTaskResult<'T, 'Error> = if __useResumableCode then - __stateMachine, CancellableTaskResult<'T, 'Error>> + __stateMachine, CancellableTaskResult<'T, 'Error>> (MoveNextMethodImpl<_>(fun sm -> //-- RESUMABLE CODE START __resumeAt sm.ResumptionPoint @@ -347,23 +101,18 @@ module CancellableTaskResultCE = try let __stack_code_fin = code.Invoke(&sm) - if - __stack_code_fin - && not sm.Data.IsTaskCompleted - then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) + if __stack_code_fin then + MethodBuilder.SetResult(&sm.Data.MethodBuilder, sm.Data.Result) with exn -> __stack_exn <- exn // Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567 match __stack_exn with | null -> () - | exn -> - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn + | exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn) //-- RESUMABLE CODE END )) (SetStateMachineMethodImpl<_>(fun sm state -> - sm.Data.MethodBuilder.SetStateMachine(state) + MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state) )) (AfterCode<_, _>(fun sm -> let sm = sm @@ -376,7 +125,7 @@ module CancellableTaskResultCE = sm.Data.CancellationToken <- ct sm.Data.MethodBuilder <- - CancellableTaskResultMethodBuilder<'T, 'Error>.Create() + AsyncTaskMethodBuilder>.Create() sm.Data.MethodBuilder.Start(&sm) sm.Data.MethodBuilder.Task @@ -384,12 +133,74 @@ module CancellableTaskResultCE = else CancellableTaskResultBuilder.RunDynamic(code) + /// Specify a Source of CancellationToken -> Task<_> on the real type to allow type inference to work + member inline _.Source + (x: CancellationToken -> Task<_>) + : CancellationToken -> Awaiter, _> = + fun ct -> Awaitable.GetTaskAwaiter(x ct) + + // member inline this.MergeSources + // ( + // [] left: CancellationToken -> 'Awaiter1, + // [] right: CancellationToken -> 'Awaiter2 + // ) = + // this.Run( + // this.Bind( + // left, + // fun leftR -> this.BindReturn(right, (fun rightR -> struct (leftR, rightR))) + // ) + // ) + // >> Awaitable.GetTaskAwaiter + + + // member inline this.MergeSources + // ( + // left: 'Awaiter1, + // [] right: CancellationToken -> 'Awaiter2 + // ) = + // this.Run( + // this.Bind( + // left, + // fun leftR -> this.BindReturn(right, (fun rightR -> struct (leftR, rightR))) + // ) + // ) + // >> Awaitable.GetTaskAwaiter + + + // member inline this.MergeSources + // ( + // [] left: CancellationToken -> 'Awaiter1, + // right: 'Awaiter2 + // ) = + // this.Run( + // this.Bind( + // left, + // fun leftR -> this.BindReturn(right, (fun rightR -> struct (leftR, rightR))) + // ) + // ) + // >> Awaitable.GetTaskAwaiter + + + // member inline this.MergeSources(left: 'Awaiter1, right: 'Awaiter2) = + // this.Run( + // this.Bind( + // left, + // fun leftR -> this.BindReturn(right, (fun rightR -> struct (leftR, rightR))) + // ) + // ) + // >> Awaitable.GetTaskAwaiter + + + /// Contains methods to build CancellableTasks using the F# computation expression syntax type BackgroundCancellableTaskResultBuilder() = inherit CancellableTaskResultBuilderBase() + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// static member inline RunDynamic - (code: CancellableTaskResultCode<'T, 'Error, 'T>) + (code: CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, _>) : CancellableTaskResult<'T, 'Error> = // backgroundTask { .. } escapes to a background thread where necessary // See spec of ConfigureAwait(false) at https://devblogs.microsoft.com/dotnet/configureawait-faq/ @@ -405,32 +216,34 @@ module CancellableTaskResultCE = ct ) - /// Same as CancellableTaskResultBuilder.Run except the start is inside Task.Run if necessary + /// + /// Hosts the task code in a state machine and starts the task, executing in the ThreadPool using Task.Run + /// member inline _.Run - (code: CancellableTaskResultCode<'T, 'Error, 'T>) + (code: CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error, _>) : CancellableTaskResult<'T, 'Error> = if __useResumableCode then - __stateMachine, CancellableTaskResult<'T, 'Error>> + __stateMachine, CancellableTaskResult<'T, 'Error>> (MoveNextMethodImpl<_>(fun sm -> //-- RESUMABLE CODE START __resumeAt sm.ResumptionPoint + let mutable __stack_exn: Exception = null try let __stack_code_fin = code.Invoke(&sm) - if - __stack_code_fin - && not sm.Data.IsTaskCompleted - then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) + if __stack_code_fin then + MethodBuilder.SetResult(&sm.Data.MethodBuilder, sm.Data.Result) with exn -> - - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn + __stack_exn <- exn + // Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567 + match __stack_exn with + | null -> () + | exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn) //-- RESUMABLE CODE END )) (SetStateMachineMethodImpl<_>(fun sm state -> - sm.Data.MethodBuilder.SetStateMachine(state) + MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state) )) (AfterCode<_, CancellableTaskResult<'T, 'Error>>(fun sm -> // backgroundTask { .. } escapes to a background thread where necessary @@ -448,7 +261,7 @@ module CancellableTaskResultCE = sm.Data.CancellationToken <- ct sm.Data.MethodBuilder <- - CancellableTaskResultMethodBuilder<'T, 'Error>.Create() + AsyncTaskMethodBuilder>.Create() sm.Data.MethodBuilder.Start(&sm) sm.Data.MethodBuilder.Task @@ -465,7 +278,7 @@ module CancellableTaskResultCE = sm.Data.CancellationToken <- ct sm.Data.MethodBuilder <- - CancellableTaskResultMethodBuilder<'T, 'Error> + AsyncTaskMethodBuilder> .Create() sm.Data.MethodBuilder.Start(&sm) @@ -474,374 +287,176 @@ module CancellableTaskResultCE = ct ) )) + else BackgroundCancellableTaskResultBuilder.RunDynamic(code) - + /// Contains the cancellableTask computation expression builder. [] module CancellableTaskResultBuilder = + /// + /// Builds a cancellableTask using computation expression syntax. + /// let cancellableTaskResult = CancellableTaskResultBuilder() - let backgroundCancellableTaskResult = BackgroundCancellableTaskResultBuilder() - - [] - module LowPriority = - // Low priority extensions - type CancellableTaskResultBuilderBase with - - [] - static member inline BindDynamic<'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error - when ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>)> - ( - sm: - byref>>, - getAwaiter: CancellationToken -> ^Awaiter, - continuation: - ('TResult1 -> CancellableTaskResultCode<'TOverall, 'Error, 'TResult2>) - ) : bool = - sm.Data.CancellationToken.ThrowIfCancellationRequested() - - let mutable awaiter = getAwaiter sm.Data.CancellationToken - - let cont = - (CancellableTaskResultResumptionFunc<'TOverall, 'Error>(fun sm -> - let result = - (^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>) (awaiter)) - - match result with - | Ok result -> (continuation result).Invoke(&sm) - | Error e -> - sm.Data.Result <- Error e - true - )) - // shortcut to continue immediately - if (^Awaiter: (member get_IsCompleted: unit -> bool) (awaiter)) then - cont.Invoke(&sm) - else - sm.ResumptionDynamicInfo.ResumptionData <- - (awaiter :> ICriticalNotifyCompletion) - - sm.ResumptionDynamicInfo.ResumptionFunc <- cont - false - - [] - member inline _.Bind<'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error - when ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>)> - ( - getAwaiter: CancellationToken -> ^Awaiter, - continuation: - ('TResult1 -> CancellableTaskResultCode<'TOverall, 'Error, 'TResult2>) - ) : CancellableTaskResultCode<'TOverall, 'Error, 'TResult2> = - - CancellableTaskResultCode<'TOverall, _, _>(fun sm -> - if __useResumableCode then - //-- RESUMABLE CODE START - sm.Data.CancellationToken.ThrowIfCancellationRequested() - // Get an awaiter from the awaitable - let mutable awaiter = getAwaiter sm.Data.CancellationToken - - let mutable __stack_fin = true - - if not (^Awaiter: (member get_IsCompleted: unit -> bool) (awaiter)) then - // This will yield with __stack_yield_fin = false - // This will resume with __stack_yield_fin = true - let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) - __stack_fin <- __stack_yield_fin - - if __stack_fin then - let result = - (^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>) (awaiter)) - - match result with - | Ok result -> (continuation result).Invoke(&sm) - | Error e -> - sm.Data.Result <- Error e - true - else - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) - false - else - CancellableTaskResultBuilderBase.BindDynamic<'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error>( - &sm, - getAwaiter, - continuation - ) - //-- RESUMABLE CODE END - ) - - [] - member inline this.ReturnFrom<'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error - when ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>)> - (getAwaiter: CancellationToken -> ^Awaiter) - : CancellableTaskResultCode<'TResult1, 'Error, 'TResult1> = - - this.Bind(getAwaiter, (fun v -> this.Return v)) - - - [] - member inline _.Source<'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error - when ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>)> - (getAwaiter: CancellationToken -> ^Awaiter) - : CancellationToken -> ^Awaiter = - getAwaiter - - [] - member inline _.Source< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter, 'TOverall, 'Error - when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter) - and ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Result<'TResult1, 'Error>)> - (task: ^TaskLike) - : CancellationToken -> ^Awaiter = - (fun (ct: CancellationToken) -> - (^TaskLike: (member GetAwaiter: unit -> ^Awaiter) (task)) - ) - - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult, 'Error - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - (t: 'Awaitable) - : CancellableTaskResult<'TResult, 'Error> = - - cancellableTask { - let! r = t - return Ok r - } - - - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult, 'Error - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - (t: unit -> 'Awaitable) - : CancellableTaskResult<'TResult, 'Error> = - - cancellableTask { - let! r = t - return Ok r - } - - - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult, 'Error - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - (t: CancellationToken -> 'Awaitable) - : CancellableTaskResult<'TResult, 'Error> = - - cancellableTask { - let! r = t - return Ok r - } - - member inline _.Using<'Resource, 'TOverall, 'Error, 'T when 'Resource :> IDisposable> - ( - resource: 'Resource, - binder: 'Resource -> CancellableTaskResultCode<'TOverall, 'Error, 'T> - ) = - ResumableCode.Using( - resource, - fun resource -> - CancellableTaskResultCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (binder resource).Invoke(&sm) - ) - ) - - [] - module HighPriority = - type Microsoft.FSharp.Control.Async with - - static member inline AwaitCancellableTaskResult - ([] t: CancellableTaskResult<'T, 'Error>) - = - async { - let! ct = Async.CancellationToken - - return! - t ct - |> Async.AwaitTask - } - - static member inline AsCancellableTaskResult(computation: Async<'T>) = - fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) + /// + /// Builds a cancellableTask using computation expression syntax which switches to execute on a background thread if not already doing so. + /// + let backgroundCancellableTaskResult = BackgroundCancellableTaskResultBuilder() - type CancellableTaskResultBuilderBase with - member inline this.Bind - ( - task: CancellableTaskResult<'TResult1, 'Error>, - continuation: - ('TResult1 -> CancellableTaskResultCode<'TOverall, 'Error, 'TResult2>) - ) : CancellableTaskResultCode<'TOverall, 'Error, 'TResult2> = - this.Bind((fun ct -> (task ct).GetAwaiter()), continuation) +// /// +// /// A set of extension methods making it possible to bind against in async computations. +// /// +// [] +// module AsyncExtensions = - member inline this.ReturnFrom - (task: CancellableTaskResult<'T, 'Error>) - : CancellableTaskResultCode<'T, 'Error, 'T> = - this.Bind(task, (fun v -> this.Return v)) +// type AsyncExBuilder with +// member inline this.Source([] t: CancellableTask<'T>) : Async<'T> = +// AsyncEx.AwaitCancellableTask t - [] - module MediumPriority = - open HighPriority +// member inline this.Source([] t: CancellableTask) : Async = +// AsyncEx.AwaitCancellableTask t - type CancellableTaskResultBuilder with +// type Microsoft.FSharp.Control.AsyncBuilder with - member inline _.Source(t: Task<'T>) = - cancellableTask { - let! r = t - return Ok r - } +// member inline this.Bind +// ( +// [] t: CancellableTask<'T>, +// [] binder: ('T -> Async<'U>) +// ) : Async<'U> = +// this.Bind(Async.AwaitCancellableTask t, binder) - member inline _.Source(result: CancellableTask<'T>) = - cancellableTask { - let! r = result - return Ok r - } +// member inline this.ReturnFrom([] t: CancellableTask<'T>) : Async<'T> = +// this.ReturnFrom(Async.AwaitCancellableTask t) - member inline _.Source(result: CancellableTask) : CancellableTaskResult = - cancellableTask { - let! r = result - return Ok r - } +// member inline this.Bind +// ( +// [] t: CancellableTask, +// [] binder: (unit -> Async<'U>) +// ) : Async<'U> = +// this.Bind(Async.AwaitCancellableTask t, binder) - member inline _.Source(result: ColdTask<_>) : CancellableTaskResult<_, _> = - cancellableTask { - let! r = result - return Ok r - } +// member inline this.ReturnFrom([] t: CancellableTask) : Async = +// this.ReturnFrom(Async.AwaitCancellableTask t) - member inline _.Source(result: ColdTask) : CancellableTaskResult<_, _> = - cancellableTask { - let! r = result - return Ok r - } +// // There is explicitly no Binds for `CancellableTasks` in `Microsoft.FSharp.Control.TaskBuilderBase`. +// // You need to explicitly pass in a `CancellationToken`to start it, you can use `CancellationToken.None`. +// // Reason is I don't want people to assume cancellation is happening without the caller being explicit about where the CancellationToken came from. +// // Similar reasoning for `IcedTasks.ColdTasks.ColdTaskBuilderBase`. - member inline _.Source(t: Async<'T>) : CancellableTaskResult<'T, 'Error> = - cancellableTask { - let! r = t - return Ok r - } +// // Contains a set of standard functional helper function +[] +module CancellableTaskResult = + open System.Threading.Tasks + open System.Threading + open IcedTasks - [] - module AsyncExtenions = - type Microsoft.FSharp.Control.AsyncBuilder with - - member inline this.Bind - ( - [] t: CancellableTaskResult<'T, 'Error>, - [] binder: (_ -> Async<_>) - ) : Async<_> = - this.Bind(Async.AwaitCancellableTaskResult t, binder) - - member inline this.ReturnFrom([] t: CancellableTaskResult<'T, 'Error>) = - this.ReturnFrom(Async.AwaitCancellableTaskResult t) - - - type FsToolkit.ErrorHandling.AsyncResultCE.AsyncResultBuilder with - - member inline this.Source - ([] t: CancellableTaskResult<'T, 'Error>) - : Async<_> = - Async.AwaitCancellableTaskResult t - - // There is explicitly no Binds for `CancellableTaskResults` in `Microsoft.FSharp.Control.TaskBuilderBase`. - // You need to explicitly pass in a `CancellationToken`to start it, you can use `CancellationToken.None`. - // Reason is I don't want people to assume cancellation is happening without the caller being explicit about where the CancellationToken came from. - - [] - module CancellableTaskResult = - let getCancellationToken () : CancellableTaskResult = - CancellableTaskResultBuilder.cancellableTaskResult.Run( - CancellableTaskResultCode<_, 'Error, _>(fun sm -> - sm.Data.Result <- Ok sm.Data.CancellationToken - true - ) - ) - - /// Lifts an item to a CancellableTaskResult. - /// The item to be the result of the CancellableTaskResult. - /// A CancellableTaskResult with the item as the result. - let inline singleton (item: 'item) : CancellableTaskResult<'item, 'Error> = - fun _ -> Task.FromResult(Ok item) - - - /// Allows chaining of CancellableTaskResult. - /// The continuation. - /// The value. - /// The result of the binder. - let inline bind - ([] binder: 'input -> CancellableTaskResult<'output, 'error>) - ([] cTask: CancellableTaskResult<'input, 'error>) - = - cancellableTaskResult { - let! cResult = cTask - return! binder cResult - } - - /// Allows chaining of CancellableTaskResult. - /// The continuation. - /// The value. - /// The result of the mapper wrapped in a CancellableTaskResult. - let inline map - ([] mapper: 'input -> 'output) - ([] cTask: CancellableTaskResult<'input, 'error>) - = - cancellableTaskResult { - let! cResult = cTask - return mapper cResult - } - - /// Allows chaining of CancellableTaskResult. - /// A function wrapped in a CancellableTaskResult - /// The value. - /// The result of the applicable. - let inline apply - ([] applicable: CancellableTaskResult<'input -> 'output, 'error>) - ([] cTask: CancellableTaskResult<'input, 'error>) - = - cancellableTaskResult { - let! applier = applicable - let! cResult = cTask - return applier cResult - } - - /// Takes two CancellableTaskResult, starts them serially in order of left to right, and returns a tuple of the pair. - /// The left value. - /// The right value. - /// A tuple of the parameters passed in - let inline zip - ([] left: CancellableTaskResult<'left, 'error>) - ([] right: CancellableTaskResult<'right, 'error>) - = - cancellableTaskResult { - let! r1 = left - let! r2 = right - return r1, r2 - } - - /// Takes two CancellableTaskResult, starts them concurrently, and returns a tuple of the pair. - /// The left value. - /// The right value. - /// A tuple of the parameters passed in. - let inline parallelZip - ([] left: CancellableTaskResult<'left, 'error>) - ([] right: CancellableTaskResult<'right, 'error>) - = - cancellableTaskResult { - let! ct = getCancellationToken () - let r1 = left ct - let r2 = right ct - let! r1 = r1 - let! r2 = r2 - return r1, r2 - } + /// Gets the default cancellation token for executing computations. + /// + /// The default CancellationToken. + /// + /// Cancellation and Exceptions + /// + /// + /// + /// use tokenSource = new CancellationTokenSource() + /// let primes = [ 2; 3; 5; 7; 11 ] + /// for i in primes do + /// let computation = + /// cancellableTask { + /// let! cancellationToken = CancellableTask.getCancellationToken() + /// do! Task.Delay(i * 1000, cancellationToken) + /// printfn $"{i}" + /// } + /// computation tokenSource.Token |> ignore + /// Thread.Sleep(6000) + /// tokenSource.Cancel() + /// printfn "Tasks Finished" + /// + /// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation and then + /// followed by "Tasks Finished". + /// + let inline getCancellationToken () = + fun (ct: CancellationToken) -> ValueTask ct + + /// Lifts an item to a CancellableTask. + /// The item to be the result of the CancellableTask. + /// A CancellableTask with the item as the result. + let inline singleton (item: 'item) : CancellableTaskResult<'item, 'Error> = + fun _ -> Task.FromResult(Ok item) + + + /// Allows chaining of CancellableTasks. + /// The continuation. + /// The value. + /// The result of the binder. + let inline bind + ([] binder: 'input -> CancellableTaskResult<'output, 'Error>) + ([] cTask: CancellableTaskResult<'input, 'Error>) + = + cancellableTaskResult { + let! cResult = cTask + return! binder cResult + } + + /// Allows chaining of CancellableTasks. + /// The continuation. + /// The value. + /// The result of the mapper wrapped in a CancellableTasks. + let inline map + ([] mapper: 'input -> 'output) + ([] cTask: CancellableTaskResult<'input, 'Error>) + = + cancellableTaskResult { + let! cResult = cTask + return mapper cResult + } + + /// Allows chaining of CancellableTasks. + /// A function wrapped in a CancellableTasks + /// The value. + /// The result of the applicable. + let inline apply + ([] applicable: CancellableTaskResult<'input -> 'output, 'Error>) + ([] cTask: CancellableTaskResult<'input, 'Error>) + = + cancellableTaskResult { + let! (applier: 'input -> 'output) = applicable + let! (cResult: 'input) = cTask + return applier cResult + } + + /// Takes two CancellableTasks, starts them serially in order of left to right, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in + let inline zip + ([] left: CancellableTaskResult<'left, 'Error>) + ([] right: CancellableTaskResult<'right, 'Error>) + = + cancellableTaskResult { + let! r1 = left + let! r2 = right + return r1, r2 + } + + /// Takes two CancellableTask, starts them concurrently, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in. + let inline parallelZip + ([] left: CancellableTaskResult<'left, 'Error>) + ([] right: CancellableTaskResult<'right, 'Error>) + = + cancellableTask { + let! ct = getCancellationToken () + let r1 = left ct + let r2 = right ct + let! r1 = r1 + let! r2 = r2 + return Result.zip r1 r2 + } diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskValidationCE.fs b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskValidationCE.fs index 208879fd..1ff8ba5e 100644 --- a/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskValidationCE.fs +++ b/src/FsToolkit.ErrorHandling.IcedTasks/CancellableTaskValidationCE.fs @@ -1,6 +1,49 @@ namespace FsToolkit.ErrorHandling +// What's going on here? +// +// F# method overload resolution has some weird quirks we're taking advantage of to allow +// for binding (`let!/do!/return!`) many various types (Such as Task/Async/Result/Validation) +// in a computation expression. .The gist is, any member methods attached to the type itself +// (the Builder object) will be preferred above all else when selection overloads to resolve. It +// will then use the the most recent Extension Methods that have been opened. The way we structure +// these overloads is to provide the most "concrete" overloads first, and then the more generic +// ones later. For example, `Validation` is defined as a `Result<'T, 'Error list>`, but we also +// want to be able to bind to `Result` itself and create a list of errors from it. So we need to +// have a `Validation` member method in a higher module, and then a `Result` member method +// somewhere lower. Another example is `Task>` vs `Task<'T>`. We want to be able +// to bind to both, so we need to have a `Task>` member method in a higher +// module, and then a `Task<'T>` member method somewhere lower. + +// NoEagerConstraintApplication also changes behavior of SRTP methods, read the +// TaskBuilder RFC for more info. + +// The reason we do AutoOpens here instead of using the attribute on the module itself +// is because it may restrict how the implementation is relying on other sections, such as +// The MediumPriority module may use something from the HighPriority module. If we put the +// HighPriority module after the MediumPriority module it will fail to compile. So we don't want +// the order of the code itself to determine the priority, this allows us to control that ordering +// more explicitly. +// +// Additional readings: +// - [F# Computation Expression Method Overload Resolution Ordering](https://gist.github.com/TheAngryByrd/c8b9c8ebcda3bb162f425bfb281d2e2b) +// - [F# RFC FS-1097 - Task builder](https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1097-task-builder.md#feature-noeagerconstraintapplicationattribute) +// - ["Most concrete" tiebreaker for generic overloads](https://github.com/fsharp/fslang-suggestions/issues/905) + + +// [] +// [] +// [] +// [] +// [] +// [] +// [] +// [] +// do () + + +/// Contains methods to build CancellableTasks using the F# computation expression syntax [] module CancellableTaskValidationCE = @@ -13,327 +56,17 @@ module CancellableTaskValidationCE = open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators open Microsoft.FSharp.Collections - open FsToolkit.ErrorHandling open IcedTasks - /// CancellationToken -> Task> - type CancellableTaskValidation<'T, 'Error> = CancellableTask> - /// The extra data stored in ResumableStateMachine for tasks - [] - type CancellableTaskValidationStateMachineData<'T, 'Error> = - [] - val mutable CancellationToken: CancellationToken + /// CancellationToken -> Task> + type CancellableTaskValidation<'T, 'Error> = CancellableTask> - [] - val mutable Result: Result<'T, 'Error list> - - [] - val mutable MethodBuilder: CancellableTaskValidationMethodBuilder<'T, 'Error> - - member inline this.IsResultError = Result.isError this.Result - - member inline this.ThrowIfCancellationRequested() = - this.CancellationToken.ThrowIfCancellationRequested() - - and CancellableTaskValidationMethodBuilder<'TOverall, 'Error> = - AsyncTaskMethodBuilder> - - and CancellableTaskValidationStateMachine<'TOverall, 'Error> = - ResumableStateMachine> - - and CancellableTaskValidationResumptionFunc<'TOverall, 'Error> = - ResumptionFunc> - - and CancellableTaskValidationResumptionDynamicInfo<'TOverall, 'Error> = - ResumptionDynamicInfo> - - and CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - ResumableCode, 'T> - - type CancellableTaskValidationBuilderBase() = - - member inline _.Delay - ([] generator: - unit -> CancellableTaskValidationCode<'TOverall, 'Error, 'T>) - : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - CancellableTaskValidationCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (generator ()).Invoke(&sm) - ) - - /// Used to represent no-ops like the implicit empty "else" branch of an "if" expression. - [] - member inline _.Zero<'TOverall, 'Error> - () - : CancellableTaskValidationCode<'TOverall, 'Error, unit> = - ResumableCode.Zero() - - member inline _.Return(value: 'T) : CancellableTaskValidationCode<'T, 'Error, 'T> = - CancellableTaskValidationCode<'T, _, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - sm.Data.Result <- Ok value - true - ) - - - /// Chains together a step with its following step. - /// Note that this requires that the first step has no result. - /// This prevents constructs like `task { return 1; return 2; }`. - member inline _.Combine - ( - [] task1: CancellableTaskValidationCode<'TOverall, 'Error, unit>, - [] task2: CancellableTaskValidationCode<'TOverall, 'Error, 'T> - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - ResumableCode.Combine( - CancellableTaskValidationCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - task1.Invoke(&sm) - ), - CancellableTaskValidationCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - if sm.Data.IsResultError then true else task2.Invoke(&sm) - ) - ) - - - /// Builds a step that executes the body while the condition predicate is true. - member inline _.While - ( - [] condition: unit -> bool, - [] body: CancellableTaskValidationCode<'TOverall, 'Error, unit> - ) : CancellableTaskValidationCode<'TOverall, 'Error, unit> = - let mutable __stack_keepGoing = true - - ResumableCode.While( - (fun () -> - __stack_keepGoing - && condition () - ), - CancellableTaskValidationCode<_, _, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - - if sm.Data.IsResultError then - __stack_keepGoing <- false - true - else - body.Invoke(&sm) - ) - ) - - /// Wraps a step in a try/with. This catches exceptions both in the evaluation of the function - /// to retrieve the step, and in the continuation of the step (if any). - member inline _.TryWith - ( - [] computation: CancellableTaskValidationCode<'TOverall, 'Error, 'T>, - [] catchHandler: - exn -> CancellableTaskValidationCode<'TOverall, 'Error, 'T> - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - ResumableCode.TryWith( - CancellableTaskValidationCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - computation.Invoke(&sm) - ), - catchHandler - ) - - /// Wraps a step in a try/finally. This catches exceptions both in the evaluation of the function - /// to retrieve the step, and in the continuation of the step (if any). - member inline _.TryFinally - ( - [] computation: CancellableTaskValidationCode<'TOverall, 'Error, 'T>, - [] compensation: unit -> unit - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - ResumableCode.TryFinally( - - CancellableTaskValidationCode(fun sm -> - sm.Data.ThrowIfCancellationRequested() - computation.Invoke(&sm) - ), - ResumableCode<_, _>(fun _ -> - compensation () - true - ) - ) - - member inline this.For - ( - sequence: seq<'T>, - [] body: - 'T -> CancellableTaskValidationCode<'TOverall, 'Error, unit> - ) : CancellableTaskValidationCode<'TOverall, 'Error, unit> = - ResumableCode.Using( - sequence.GetEnumerator(), - // ... and its body is a while loop that advances the enumerator and runs the body on each element. - (fun e -> - this.While( - (fun () -> e.MoveNext()), - CancellableTaskValidationCode<'TOverall, 'Error, unit>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (body e.Current).Invoke(&sm) - ) - ) - ) - ) - - member inline internal this.TryFinallyAsync - ( - [] body: CancellableTaskValidationCode<'TOverall, 'Error, 'T>, - [] compensation: unit -> ValueTask - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - ResumableCode.TryFinallyAsync( - body, - ResumableCode<_, _>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - - if __useResumableCode then - let mutable __stack_condition_fin = true - let __stack_vtask = compensation () - - if not __stack_vtask.IsCompleted then - let mutable awaiter = __stack_vtask.GetAwaiter() - let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) - __stack_condition_fin <- __stack_yield_fin - - if not __stack_condition_fin then - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) - - __stack_condition_fin - else - let vtask = compensation () - let mutable awaiter = vtask.GetAwaiter() - - let cont = - CancellableTaskValidationResumptionFunc<'TOverall, 'Error>(fun sm -> - awaiter.GetResult() - |> ignore - - true - ) - - // shortcut to continue immediately - if awaiter.IsCompleted then - true - else - sm.ResumptionDynamicInfo.ResumptionData <- - (awaiter :> ICriticalNotifyCompletion) - - sm.ResumptionDynamicInfo.ResumptionFunc <- cont - false - ) - ) - - member inline this.Using<'Resource, 'TOverall, 'Error, 'T when 'Resource :> IAsyncDisposable> - ( - resource: 'Resource, - [] body: - 'Resource -> CancellableTaskValidationCode<'TOverall, 'Error, 'T> - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'T> = - this.TryFinallyAsync( - (fun sm -> (body resource).Invoke(&sm)), - (fun () -> - if not (isNull (box resource)) then - resource.DisposeAsync() - else - ValueTask() - ) - ) - - - [] - static member inline BindDynamic - ( - sm: - byref>>, - [] getAwaiter: CancellationToken -> ^Awaiter, - [] continuation: - ('TResult1 -> CancellableTaskValidationCode<'TOverall, 'Error, 'TResult2>) - ) : bool = - sm.Data.CancellationToken.ThrowIfCancellationRequested() - - let mutable awaiter = getAwaiter sm.Data.CancellationToken - - let cont = - (CancellableTaskValidationResumptionFunc<'TOverall, 'Error>(fun sm -> - let result = Awaiter.GetResult awaiter - - match result with - | Ok result -> (continuation result).Invoke(&sm) - | Error e -> - sm.Data.Result <- Error e - true - )) - - // shortcut to continue immediately - if Awaiter.IsCompleted awaiter then - cont.Invoke(&sm) - else - sm.ResumptionDynamicInfo.ResumptionData <- (awaiter :> ICriticalNotifyCompletion) - - sm.ResumptionDynamicInfo.ResumptionFunc <- cont - false - - [] - member inline _.Bind - ( - [] getAwaiter: CancellationToken -> ^Awaiter, - [] continuation: - ('TResult1 -> CancellableTaskValidationCode<'TOverall, 'Error, 'TResult2>) - ) : CancellableTaskValidationCode<'TOverall, 'Error, 'TResult2> = - - CancellableTaskValidationCode<'TOverall, _, _>(fun sm -> - if __useResumableCode then - //-- RESUMABLE CODE START - sm.Data.CancellationToken.ThrowIfCancellationRequested() - // Get an awaiter from the awaitable - let mutable awaiter = getAwaiter sm.Data.CancellationToken - - let mutable __stack_fin = true - - if not (Awaiter.IsCompleted awaiter) then - // This will yield with __stack_yield_fin = false - // This will resume with __stack_yield_fin = true - let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) - __stack_fin <- __stack_yield_fin - - if __stack_fin then - match Awaiter.GetResult awaiter with - | Ok result -> (continuation result).Invoke(&sm) - | Error e -> - sm.Data.Result <- Error e - true - else - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) - false - else - CancellableTaskValidationBuilderBase.BindDynamic(&sm, getAwaiter, continuation) - //-- RESUMABLE CODE END - ) - - - member inline this.Source(xs: #seq<_>) = xs - - - [] - member inline this.ReturnFrom - ([] getAwaiter: CancellationToken -> ^Awaiter) - : CancellableTaskValidationCode<'TResult1, 'Error, 'TResult1> = - - this.Bind(getAwaiter, (fun v -> this.Return v)) - - - [] - member inline this.BindReturn - ( - [] getAwaiter: CancellationToken -> ^Awaiter, - [] f: 'a -> 'TResult1 - ) : CancellableTaskValidationCode<'TResult1, 'Error, 'TResult1> = - - this.Bind(getAwaiter, (fun v -> this.Return(f v))) + /// Contains methods to build CancellableTasks using the F# computation expression syntax type CancellableTaskValidationBuilder() = - inherit CancellableTaskValidationBuilderBase() + inherit CancellableTaskResultBuilderBase() // This is the dynamic implementation - this is not used // for statically compiled tasks. An executor (resumptionFuncExecutor) is @@ -341,17 +74,23 @@ module CancellableTaskValidationCE = // The executor stays constant throughout the execution, it wraps each step // of the execution in a try/with. The resumption is changed at each step // to represent the continuation of the computation. + /// + /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code. + /// static member inline RunDynamic - ([] code: CancellableTaskValidationCode<'T, 'Error, 'T>) + (code: + CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error list, AsyncTaskMethodBuilder>>) : CancellableTaskValidation<'T, 'Error> = - let mutable sm = CancellableTaskValidationStateMachine<'T, 'Error>() + let mutable sm = CancellableTaskResultBuilderBaseStateMachine<'T, 'Error list, _>() let initialResumptionFunc = - CancellableTaskValidationResumptionFunc<'T, 'Error>(fun sm -> code.Invoke(&sm)) + CancellableTaskResultBuilderBaseResumptionFunc<'T, 'Error list, _>(fun sm -> + code.Invoke(&sm) + ) let resumptionInfo = - { new CancellableTaskValidationResumptionDynamicInfo<'T, 'Error>(initialResumptionFunc) with + { new CancellableTaskResultBuilderBaseResumptionDynamicInfo<'T, 'Error list, _>(initialResumptionFunc) with member info.MoveNext(sm) = let mutable savedExn = null @@ -360,26 +99,28 @@ module CancellableTaskValidationCE = let step = info.ResumptionFunc.Invoke(&sm) if step then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) + // sm.Data.MethodBuilder.SetResult sm.Data.Result + MethodBuilder.SetResult(&sm.Data.MethodBuilder, sm.Data.Result) else let mutable awaiter = sm.ResumptionDynamicInfo.ResumptionData :?> ICriticalNotifyCompletion - assert not (isNull awaiter) - sm.Data.MethodBuilder.AwaitUnsafeOnCompleted(&awaiter, &sm) + MethodBuilder.AwaitUnsafeOnCompleted( + &sm.Data.MethodBuilder, + &awaiter, + &sm + ) with exn -> savedExn <- exn // Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567 match savedExn with | null -> () - | exn -> - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn + | exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn) member _.SetStateMachine(sm, state) = - sm.Data.MethodBuilder.SetStateMachine(state) + MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state) } fun (ct) -> @@ -388,18 +129,17 @@ module CancellableTaskValidationCE = else sm.Data.CancellationToken <- ct sm.ResumptionDynamicInfo <- resumptionInfo - - sm.Data.MethodBuilder <- - CancellableTaskValidationMethodBuilder<'T, 'Error>.Create() - + sm.Data.MethodBuilder <- AsyncTaskMethodBuilder>.Create() sm.Data.MethodBuilder.Start(&sm) sm.Data.MethodBuilder.Task + + /// Hosts the task code in a state machine and starts the task. member inline _.Run - ([] code: CancellableTaskValidationCode<'T, 'Error, 'T>) + (code: CancellableTaskResultBuilderBaseCode<'T, 'T, 'Error list, _>) : CancellableTaskValidation<'T, 'Error> = if __useResumableCode then - __stateMachine, CancellableTaskValidation<'T, 'Error>> + __stateMachine>>, CancellableTaskValidation<'T, 'Error>> (MoveNextMethodImpl<_>(fun sm -> //-- RESUMABLE CODE START __resumeAt sm.ResumptionPoint @@ -409,19 +149,18 @@ module CancellableTaskValidationCE = let __stack_code_fin = code.Invoke(&sm) if __stack_code_fin then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) + // sm.Data.MethodBuilder.SetResult sm.Data.Result + MethodBuilder.SetResult(&sm.Data.MethodBuilder, sm.Data.Result) with exn -> __stack_exn <- exn // Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567 match __stack_exn with | null -> () - | exn -> - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn + | exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn) //-- RESUMABLE CODE END )) (SetStateMachineMethodImpl<_>(fun sm state -> - sm.Data.MethodBuilder.SetStateMachine(state) + MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state) )) (AfterCode<_, _>(fun sm -> let sm = sm @@ -434,664 +173,916 @@ module CancellableTaskValidationCE = sm.Data.CancellationToken <- ct sm.Data.MethodBuilder <- - CancellableTaskValidationMethodBuilder<'T, 'Error>.Create() + AsyncTaskMethodBuilder>.Create() sm.Data.MethodBuilder.Start(&sm) sm.Data.MethodBuilder.Task )) else - CancellableTaskValidationBuilder.RunDynamic(code) + CancellableTaskResultBuilder.RunDynamic(code) - type BackgroundCancellableTaskValidationBuilder() = + /// Specify a Source of CancellationToken -> Task<_> on the real type to allow type inference to work + member inline this.Source(cancellableTaskValidation: CancellableTaskValidation<_, _>) = + this.Source(fun ct -> Awaitable.GetTaskAwaiter(cancellableTaskValidation ct)) - inherit CancellableTaskValidationBuilderBase() - static member inline RunDynamic - ([] code: CancellableTaskValidationCode<'T, 'Error, 'T>) - : CancellableTaskValidation<'T, 'Error> = - // backgroundTask { .. } escapes to a background thread where necessary - // See spec of ConfigureAwait(false) at https://devblogs.microsoft.com/dotnet/configureawait-faq/ - if - isNull SynchronizationContext.Current - && obj.ReferenceEquals(TaskScheduler.Current, TaskScheduler.Default) - then - CancellableTaskValidationBuilder.RunDynamic(code) - else - fun (ct) -> - Task.Run>( - (fun () -> CancellableTaskValidationBuilder.RunDynamic (code) (ct)), - ct + /// Contains the cancellableTask computation expression builder. + [] + module CancellableTaskResultBuilder = + + /// + /// Builds a cancellableTask using computation expression syntax. + /// + let cancellableTaskValidation = CancellableTaskValidationBuilder() + + +/// +/// A set of extension methods making it possible to bind against in async computations. +/// +[] +module AsyncExtensions = + open IcedTasks + + type AsyncExBuilder with + + member inline this.Source([] t: CancellableTask<'T>) : Async<'T> = + AsyncEx.AwaitCancellableTask t + + member inline this.Source([] t: CancellableTask) : Async = + AsyncEx.AwaitCancellableTask t + + type Microsoft.FSharp.Control.AsyncBuilder with + + member inline this.Bind + ( + [] t: CancellableTask<'T>, + [] binder: ('T -> Async<'U>) + ) : Async<'U> = + this.Bind(Async.AwaitCancellableTask t, binder) + + member inline this.ReturnFrom([] t: CancellableTask<'T>) : Async<'T> = + this.ReturnFrom(Async.AwaitCancellableTask t) + + member inline this.Bind + ( + [] t: CancellableTask, + [] binder: (unit -> Async<'U>) + ) : Async<'U> = + this.Bind(Async.AwaitCancellableTask t, binder) + + member inline this.ReturnFrom([] t: CancellableTask) : Async = + this.ReturnFrom(Async.AwaitCancellableTask t) + + + type Microsoft.FSharp.Control.Async with + + static member inline AwaitCancellableTaskValidation + ([] t: CancellableTaskValidation<'T, 'Error>) + = + async { + let! ct = Async.CancellationToken + + return! + t ct + |> Async.AwaitTask + } + + static member inline AsCancellableTaskValidation(computation: Async<'T>) = + fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) + + + type FsToolkit.ErrorHandling.AsyncValidationCE.AsyncValidationBuilder with + + member inline this.Source + ([] t: CancellableTaskValidation<'T, 'Error>) + : Async<_> = + Async.AwaitCancellableTaskValidation t + +// There is explicitly no Binds for `CancellableTasks` in `Microsoft.FSharp.Control.TaskBuilderBase`. +// You need to explicitly pass in a `CancellationToken`to start it, you can use `CancellationToken.None`. +// Reason is I don't want people to assume cancellation is happening without the caller being explicit about where the CancellationToken came from. +// Similar reasoning for `IcedTasks.ColdTasks.ColdTaskBuilderBase`. + +/// Contains a set of standard functional helper function + +[] +module CancellableTaskValidation = + open System.Threading.Tasks + open System.Threading + open IcedTasks + + /// Gets the default cancellation token for executing computations. + /// + /// The default CancellationToken. + /// + /// Cancellation and Exceptions + /// + /// + /// + /// use tokenSource = new CancellationTokenSource() + /// let primes = [ 2; 3; 5; 7; 11 ] + /// for i in primes do + /// let computation = + /// cancellableTask { + /// let! cancellationToken = CancellableTask.getCancellationToken() + /// do! Task.Delay(i * 1000, cancellationToken) + /// printfn $"{i}" + /// } + /// computation tokenSource.Token |> ignore + /// Thread.Sleep(6000) + /// tokenSource.Cancel() + /// printfn "Tasks Finished" + /// + /// This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation and then + /// followed by "Tasks Finished". + /// + let inline getCancellationToken () = + fun (ct: CancellationToken) -> ValueTask ct + + /// Lifts an item to a CancellableTask. + /// The item to be the result of the CancellableTask. + /// A CancellableTask with the item as the result. + let inline singleton (item: 'item) : CancellableTaskValidation<'item, 'Error> = + fun _ -> Task.FromResult(Ok item) + + /// Allows chaining of CancellableTasks. + /// The continuation. + /// The value. + /// The result of the binder. + let inline bind + ([] binder: 'input -> CancellableTaskValidation<'output, 'Error>) + ([] cTask: CancellableTaskValidation<'input, 'Error>) + = + cancellableTaskValidation { + let! cResult = cTask + return! binder cResult + } + + + let inline ofResult (result: Result<'ok, 'error>) : CancellableTaskValidation<'ok, 'error> = + let x = Result.mapError List.singleton result + fun _ -> Task.FromResult(x) + + /// Lifts an item to a CancellableTaskValidation. + /// The item to be the ok result of the CancellableTaskValidation. + /// A CancellableTaskValidation with the item as the result. + let inline ok (item: 'ok) : CancellableTaskValidation<'ok, 'error> = + fun _ -> Task.FromResult(Ok item) + + /// Lifts an item to a CancellableTaskValidation. + /// The item to be the error result of the CancellableTaskValidation. + /// A CancellableTaskValidation with the item as the result. + let inline error (error: 'error) : CancellableTaskValidation<'ok, 'error> = + fun _ -> Task.FromResult(Error [ error ]) + + + let inline ofChoice (choice: Choice<'ok, 'error>) : CancellableTaskValidation<'ok, 'error> = + match choice with + | Choice1Of2 x -> ok x + | Choice2Of2 x -> error x + + let inline retn (value: 'ok) : CancellableTaskValidation<'ok, 'error> = ok value + + + let inline mapError + ([] errorMapper: 'errorInput -> 'errorOutput) + ([] input: CancellableTaskValidation<'ok, 'errorInput>) + : CancellableTaskValidation<'ok, 'errorOutput> = + cancellableTask { + let! input = input + return Result.mapError (List.map errorMapper) input + } + + let inline mapErrors + ([] errorMapper: 'errorInput list -> 'errorOutput list) + ([] input: CancellableTaskValidation<'ok, 'errorInput>) + : CancellableTaskValidation<'ok, 'errorOutput> = + cancellableTask { + let! input = input + return Result.mapError errorMapper input + } + + /// Allows chaining of CancellableTaskValidation. + /// The continuation. + /// The value. + /// The result of the mapper wrapped in a CancellableTaskValidation. + let inline map + ([] mapper: 'input -> 'output) + ([] cTask: CancellableTaskValidation<'input, 'error>) + : CancellableTaskValidation<'output, 'error> = + cancellableTask { + let! cResult = cTask + return Result.map mapper cResult + } + + /// Allows chaining of CancellableTaskValidation. + /// The continuation. + /// The 1st value. + /// The 2nd value. + /// The result of the mapper wrapped in a CancellableTaskValidation. + let inline map2 + ([] mapper: 'input1 -> 'input2 -> 'output) + ([] cTask1: CancellableTaskValidation<'input1, 'error>) + ([] cTask2: CancellableTaskValidation<'input2, 'error>) + : CancellableTaskValidation<'output, 'error> = + cancellableTask { + let! cResult1 = cTask1 + let! cResult2 = cTask2 + + return + match cResult1, cResult2 with + | Ok x, Ok y -> Ok(mapper x y) + | Ok _, Error errs -> Error errs + | Error errs, Ok _ -> Error errs + | Error errs1, Error errs2 -> + Error( + errs1 + @ errs2 + ) + } + + /// Allows chaining of CancellableTaskValidation. + /// The continuation. + /// The 1st value. + /// The 2nd value. + /// The 2nd value. + /// The result of the mapper wrapped in a CancellableTaskValidation. + let inline map3 + ([] mapper: 'input1 -> 'input2 -> 'input3 -> 'output) + ([] cTask1: CancellableTaskValidation<'input1, 'error>) + ([] cTask2: CancellableTaskValidation<'input2, 'error>) + ([] cTask3: CancellableTaskValidation<'input3, 'error>) + : CancellableTaskValidation<'output, 'error> = + cancellableTask { + let! cResult1 = cTask1 + let! cResult2 = cTask2 + let! cResult3 = cTask3 + + return + match cResult1, cResult2, cResult3 with + | Ok x, Ok y, Ok z -> Ok(mapper x y z) + | Error errs, Ok _, Ok _ -> Error errs + | Ok _, Error errs, Ok _ -> Error errs + | Ok _, Ok _, Error errs -> Error errs + | Error errs1, Error errs2, Ok _ -> + Error( + errs1 + @ errs2 + ) + | Ok _, Error errs1, Error errs2 -> + Error( + errs1 + @ errs2 + ) + | Error errs1, Ok _, Error errs2 -> + Error( + errs1 + @ errs2 + ) + | Error errs1, Error errs2, Error errs3 -> + Error( + errs1 + @ errs2 + @ errs3 + ) + } + + /// Allows chaining of CancellableTaskValidation. + /// A function wrapped in a CancellableTaskValidation + /// The value. + /// The result of the applicable. + let inline apply + ([] applicable: CancellableTaskValidation<'input -> 'output, 'error>) + ([] cTask: CancellableTaskValidation<'input, 'error>) + : CancellableTaskValidation<'output, 'error> = + cancellableTask { + let! applier = applicable + let! cResult = cTask + + return + match applier, cResult with + | Ok f, Ok x -> Ok(f x) + | Error errs, Ok _ + | Ok _, Error errs -> Error errs + | Error errs1, Error errs2 -> + Error( + errs1 + @ errs2 ) + } + + let inline orElse + ([] ifError: CancellableTaskValidation<'input, 'errorOutput>) + ([] cTask: CancellableTaskValidation<'input, 'errorInput>) + : CancellableTaskValidation<'input, 'errorOutput> = + cancellableTask { + let! result = cTask + + return! + result + |> Result.either ok (fun _ -> ifError) + } + + let inline orElseWith + ([] ifErrorFunc: + 'errorInput list -> CancellableTaskValidation<'input, 'errorOutput>) + ([] cTask: CancellableTaskValidation<'input, 'errorInput>) + : CancellableTaskValidation<'input, 'errorOutput> = + cancellableTask { + let! result = cTask + + return! + match result with + | Ok x -> ok x + | Error err -> ifErrorFunc err + } + + /// Takes two CancellableTaskValidation, starts them serially in order of left to right, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in + let inline zip + ([] left: CancellableTaskValidation<'left, 'error>) + ([] right: CancellableTaskValidation<'right, 'error>) + : CancellableTaskValidation<('left * 'right), 'error> = + cancellableTask { + let! r1 = left + let! r2 = right + + return Validation.zip r1 r2 + } + + /// Takes two CancellableTaskValidation, starts them concurrently, and returns a tuple of the pair. + /// The left value. + /// The right value. + /// A tuple of the parameters passed in. + let inline parallelZip + ([] left: CancellableTaskValidation<'left, 'error>) + ([] right: CancellableTaskValidation<'right, 'error>) + : CancellableTaskValidation<('left * 'right), 'error> = + cancellableTask { + let! r1 = left + and! r2 = right + return Validation.zip r1 r2 + } + + +open IcedTasks +open System.Threading +open System.Threading.Tasks +open Microsoft.FSharp.Core.CompilerServices - /// Same as CancellableTaskValidationBuilder.Run except the start is inside Task.Run if necessary - member inline _.Run - ([] code: CancellableTaskValidationCode<'T, 'Error, 'T>) - : CancellableTaskValidation<'T, 'Error> = - if __useResumableCode then - __stateMachine, CancellableTaskValidation<'T, 'Error>> - (MoveNextMethodImpl<_>(fun sm -> - //-- RESUMABLE CODE START - __resumeAt sm.ResumptionPoint - try - let __stack_code_fin = code.Invoke(&sm) +[] +module CTVMergeSourcesExtensionsCT1CT2 = - if __stack_code_fin then - sm.Data.MethodBuilder.SetResult(sm.Data.Result) - with exn -> + type CancellableTaskValidationBuilder with - // printfn "%A" exn - sm.Data.MethodBuilder.SetException exn - //-- RESUMABLE CODE END - )) - (SetStateMachineMethodImpl<_>(fun sm state -> - sm.Data.MethodBuilder.SetStateMachine(state) - )) - (AfterCode<_, CancellableTaskValidation<'T, 'Error>>(fun sm -> - // backgroundTask { .. } escapes to a background thread where necessary - // See spec of ConfigureAwait(false) at https://devblogs.microsoft.com/dotnet/configureawait-faq/ - if - isNull SynchronizationContext.Current - && obj.ReferenceEquals(TaskScheduler.Current, TaskScheduler.Default) - then - let mutable sm = sm - - fun (ct) -> - if ct.IsCancellationRequested then - Task.FromCanceled<_>(ct) - else - sm.Data.CancellationToken <- ct - - sm.Data.MethodBuilder <- - CancellableTaskValidationMethodBuilder<'T, 'Error>.Create() - - sm.Data.MethodBuilder.Start(&sm) - sm.Data.MethodBuilder.Task - else - let sm = sm // copy contents of state machine so we can capture it - - fun (ct) -> - if ct.IsCancellationRequested then - Task.FromCanceled<_>(ct) - else - Task.Run>( - (fun () -> - let mutable sm = sm // host local mutable copy of contents of state machine on this thread pool thread - sm.Data.CancellationToken <- ct - - sm.Data.MethodBuilder <- - CancellableTaskValidationMethodBuilder<'T, 'Error> - .Create() - - sm.Data.MethodBuilder.Start(&sm) - sm.Data.MethodBuilder.Task - ), - ct - ) - )) - else - BackgroundCancellableTaskValidationBuilder.RunDynamic(code) + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) (Ok r1) + } + ) + +[] +module CTVMergeSourcesExtensionsCV1CT2 = + type CancellableTaskValidationBuilder with - module CancellableTaskValidationBuilder = + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 (Ok r1) + } + ) - let cancellableTaskValidation = CancellableTaskValidationBuilder() - let backgroundCancellableTaskValidation = - BackgroundCancellableTaskValidationBuilder() - - - module LowestPriority = - - type CancellableTaskValidationBuilderBase with - - // https://github.com/dotnet/fsharp/discussions/15567 - [] - member inline this.MergeSources<'TResult1, 'TResult2, ^Awaiter1, ^Awaiter2, 'Error - when ^Awaiter1 :> ICriticalNotifyCompletion - and ^Awaiter1: (member get_IsCompleted: unit -> bool) - and ^Awaiter1: (member GetResult: unit -> Validation<'TResult1, 'Error>) - and ^Awaiter2 :> ICriticalNotifyCompletion - and ^Awaiter2: (member get_IsCompleted: unit -> bool) - and ^Awaiter2: (member GetResult: unit -> Validation<'TResult2, 'Error>)> - ( - [] left: CancellationToken -> ^Awaiter1, - [] right: CancellationToken -> ^Awaiter2 - ) : CancellationToken -> TaskAwaiter> = - - (fun ct -> - let handler = - cancellableTask { - let! ct = CancellableTask.getCancellationToken () - let left' = left ct - let right' = right ct - let! leftResult = left' - let! rightResult = right' - - return Validation.zip leftResult rightResult - } - - (handler ct).GetAwaiter() - ) +[] +module CTVMergeSourcesExtensionsCT1CV2 = - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - ([] t: CancellationToken -> 'Awaitable) - = - - fun ct -> - (task { - let! r = t ct - return Validation.ok r - }) - .GetAwaiter() - - - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - ([] t: unit -> 'Awaitable) - = - - fun (ct: CancellationToken) -> - (task { - let! r = t () - return Validation.ok r - }) - .GetAwaiter() - - - [] - member inline this.Source<'Awaitable, 'Awaiter, 'TResult - when Awaitable<'Awaitable, 'Awaiter, 'TResult>> - (t: 'Awaitable) - = + type CancellableTaskValidationBuilder with + + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) rightR) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) r1 + } + ) - fun (ct: CancellationToken) -> - (task { - let! r = t - return Validation.ok r - }) - .GetAwaiter() - - - module LowerPriority = - - type CancellableTaskValidationBuilderBase with - - - [] - member inline this.Source([] t: CancellationToken -> 'Awaitable) = - fun ct -> - (task { - let! r = t ct - return Validation.ofResult r - }) - .GetAwaiter() - - - [] - member inline this.Source([] t: unit -> 'Awaitable) = - fun (ct: CancellationToken) -> - (task { - let! r = t () - return Validation.ofResult r - }) - .GetAwaiter() - - - [] - member inline this.Source(t: 'Awaitable) = - fun (ct: CancellationToken) -> - (task { - let! r = t - return Validation.ofResult r - }) - .GetAwaiter() - - module LowerPriority2 = - // Low priority extensions - type CancellableTaskValidationBuilderBase with - - [] - member inline this.Source<'Awaitable, ^Awaiter, 'T, 'Error - when 'Awaitable: (member GetAwaiter: unit -> ^Awaiter) - and ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Validation<'T, 'Error>)> - ([] t: CancellationToken -> 'Awaitable) - = - - fun ct -> Awaitable.GetAwaiter(t ct) - - - [] - member inline this.Source<'Awaitable, ^Awaiter, 'T, 'Error - when 'Awaitable: (member GetAwaiter: unit -> ^Awaiter) - and ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Validation<'T, 'Error>)> - ([] t: unit -> 'Awaitable) - = - - fun (ct: CancellationToken) -> Awaitable.GetAwaiter(t ()) - - - [] - member inline this.Source<'Awaitable, ^Awaiter, 'T, 'Error - when 'Awaitable: (member GetAwaiter: unit -> ^Awaiter) - and ^Awaiter :> ICriticalNotifyCompletion - and ^Awaiter: (member get_IsCompleted: unit -> bool) - and ^Awaiter: (member GetResult: unit -> Validation<'T, 'Error>)> - (t: 'Awaitable) - = - - fun (ct: CancellationToken) -> Awaitable.GetAwaiter(t) - - module LowPriority = - // Low priority extensions - type CancellableTaskValidationBuilderBase with - - member inline this.Source(t: Task<'T>) = - fun (ct: CancellationToken) -> (Task.map Validation.ok t).GetAwaiter() - - member inline this.Source([] t: ColdTask<'T>) = - fun (ct: CancellationToken) -> (Task.map Validation.ok (t ())).GetAwaiter() - - - member inline this.Source([] t: CancellableTask<'T>) = - fun (ct: CancellationToken) -> (Task.map Validation.ok (t ct)).GetAwaiter() - - member inline this.Source(t: Async<'T>) = - - fun (ct: CancellationToken) -> - (Task.map Validation.ok (Async.StartAsTask(t, cancellationToken = ct))) - .GetAwaiter() - - member inline _.Using<'Resource, 'TOverall, 'Error, 'T when 'Resource :> IDisposable> - ( - resource: 'Resource, - [] binder: - 'Resource -> CancellableTaskValidationCode<'TOverall, 'Error, 'T> - ) = - ResumableCode.Using( - resource, - fun resource -> - CancellableTaskValidationCode<'TOverall, 'Error, 'T>(fun sm -> - sm.Data.ThrowIfCancellationRequested() - (binder resource).Invoke(&sm) - ) - ) - module MediumPriority = - type Microsoft.FSharp.Control.Async with +[] +module CTVMergeSourcesExtensionsCV1CV2 = - static member inline AwaitCancellableTaskValidation - ([] t: CancellableTaskValidation<'T, 'Error>) - = - async { - let! ct = Async.CancellationToken + type CancellableTaskValidationBuilder with - return! - t ct - |> Async.AwaitTask + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR rightR) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 r1 } + ) + - static member inline AsCancellableTaskValidation(computation: Async<'T>) = - fun ct -> Async.StartImmediateAsTask(computation, cancellationToken = ct) +[] +module CTVMergeSourcesExtensionsCT1T2 = - type CancellableTaskValidationBuilderBase with + type CancellableTaskValidationBuilder with + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + right: 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) (Ok r1) + } + ) + +[] +module CTVMergeSourcesExtensionsCV1T2 = + + type CancellableTaskValidationBuilder with + + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + right: 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 (Ok r1) + } + ) + + +[] +module CTVMergeSourcesExtensionsCT1TV2 = + + type CancellableTaskValidationBuilder with + + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + right: 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) rightR) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) r1 + } + ) + + +[] +module CTVMergeSourcesExtensionsCV1TV2 = - member inline _.Source(t: Result<'T, 'Error>) = - fun (ct: CancellationToken) -> - (t - |> Validation.ofResult - |> Task.FromResult) - .GetAwaiter() + type CancellableTaskValidationBuilder with - member inline _.Source(t: Choice<'T, 'Error>) = - fun (ct: CancellationToken) -> - (t - |> Result.ofChoice - |> Validation.ofResult - |> Task.FromResult) - .GetAwaiter() + [] + member inline this.MergeSources + ( + [] left: CancellationToken -> 'Awaiter1, + right: 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let left = left ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR (rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 r1 + } + ) +[] +module CTVMergeSourcesExtensionsT1CT2 = - member inline _.Source(t: TaskResult<'T, 'Error>) = - fun (ct: CancellationToken) -> (Task.map Validation.ofResult t).GetAwaiter() + type CancellableTaskValidationBuilder with + [] + member inline this.MergeSources + ( + left: 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) (Ok r1) + } + ) - member inline _.Source(t: Async>) = - fun ct -> - (Async.StartAsTask(t, cancellationToken = ct) - |> Task.map Validation.ofResult) - .GetAwaiter() +[] +module CTVMergeSourcesExtensionsTV1CT2 = + type CancellableTaskValidationBuilder with - member inline this.Source(t: Async>) = - this.Source(Async.map Result.ofChoice t) + [] + member inline this.MergeSources + ( + left: 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 (Ok r1) + } + ) - member inline _.Source([] t: CancellableTaskResult<'T, 'Error>) = - CancellableTask.map Validation.ofResult t +[] +module CTVMergeSourcesExtensionsT1CV2 = - module HighPriority = + type CancellableTaskValidationBuilder with - type CancellableTaskValidationBuilder with + [] + member inline this.MergeSources + ( + left: 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) rightR) + // ) + // )) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) r1 + } + // ) + ) - member inline _.Source(t: Validation<'T, 'Error>) = - fun (ct: CancellationToken) -> (Task.FromResult t).GetAwaiter() +[] +module CTVMergeSourcesExtensionsTV1CV2 = + open System.Runtime.CompilerServices - member inline _.Source([] t: CancellableTaskValidation<'T, 'Error>) = - fun ct -> (t ct).GetAwaiter() + type CancellableTaskValidationBuilder with - member inline _.Source(t: Task>) = - fun (ct: CancellationToken) -> t.GetAwaiter() + [] + member inline this.MergeSources + ( + left: 'Awaiter1, + [] right: CancellationToken -> 'Awaiter2 + ) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // let right = right ct + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR rightR) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 r1 + } + // fun ct -> Awaitable.GetTaskAwaiter(IcedTasks.Polyfill.Task.Tasks.TaskBuilder.task { + // let r1 = right ct + // let l1 = left + // let! struct (l1, r1) = IcedTasks.Polyfill.Task.Tasks.TaskBuilder.task.MergeSources(l1, r1) - member inline _.Source(t: Async>) = - fun ct -> Async.StartAsTask(t, cancellationToken = ct).GetAwaiter() + // // let foo = cancellableTask.MergeSources(left, right) ct + // return Validation.zip l1 r1 + // }) + // |> ignore - module AsyncExtensions = - open MediumPriority + // Unchecked.defaultof<_> + ) - type Microsoft.FSharp.Control.AsyncBuilder with - member inline this.Bind - ( - [] t: CancellableTaskValidation<'T, 'Error>, - [] binder: (_ -> Async<_>) - ) : Async<_> = - this.Bind(Async.AwaitCancellableTaskValidation t, binder) +[] +module CTVMergeSourcesExtensionsT1T2 = - member inline this.ReturnFrom - ([] t: CancellableTaskValidation<'T, 'Error>) - = - this.ReturnFrom(Async.AwaitCancellableTaskValidation t) + type CancellableTaskValidationBuilder with + [] + member inline this.MergeSources(left: 'Awaiter1, right: 'Awaiter2) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) (Ok r1) + } + ) - type FsToolkit.ErrorHandling.AsyncValidationCE.AsyncValidationBuilder with +[] +module CTVMergeSourcesExtensionsTV1T2 = - member inline this.Source - ([] t: CancellableTaskValidation<'T, 'Error>) - : Async<_> = - Async.AwaitCancellableTaskValidation t + type CancellableTaskValidationBuilder with - [] - module CancellableTaskValidation = - let getCancellationToken () : CancellableTaskValidation = - CancellableTaskValidationBuilder.cancellableTaskValidation.Run( - CancellableTaskValidationCode<_, 'Error, _>(fun sm -> - sm.Data.Result <- Ok sm.Data.CancellationToken - true - ) + [] + member inline this.MergeSources(left: 'Awaiter1, right: 'Awaiter2) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip leftR (Ok rightR)) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 (Ok r1) + } ) - /// Lifts an item to a CancellableTaskValidation. - /// The item to be the ok result of the CancellableTaskValidation. - /// A CancellableTaskValidation with the item as the result. - let inline ok (item: 'ok) : CancellableTaskValidation<'ok, 'error> = - fun _ -> Task.FromResult(Ok item) - - /// Lifts an item to a CancellableTaskValidation. - /// The item to be the error result of the CancellableTaskValidation. - /// A CancellableTaskValidation with the item as the result. - let inline error (error: 'error) : CancellableTaskValidation<'ok, 'error> = - fun _ -> Task.FromResult(Error [ error ]) - - let inline ofResult (result: Result<'ok, 'error>) : CancellableTaskValidation<'ok, 'error> = - let x = Result.mapError List.singleton result - fun _ -> Task.FromResult(x) - - let inline ofChoice (choice: Choice<'ok, 'error>) : CancellableTaskValidation<'ok, 'error> = - match choice with - | Choice1Of2 x -> ok x - | Choice2Of2 x -> error x - - let inline retn (value: 'ok) : CancellableTaskValidation<'ok, 'error> = ok value - - /// Allows chaining of CancellableTaskValidation. - /// The continuation. - /// The value. - /// The result of the binder. - let inline bind - ([] binder: 'input -> CancellableTaskValidation<'output, 'error>) - ([] cTask: CancellableTaskValidation<'input, 'error>) - = - cancellableTask { - let! cResult = cTask - match cResult with - | Ok x -> return! binder x - | Error e -> return Error e - } +[] +module CTVMergeSourcesExtensionsT1TV2 = - let inline mapError - ([] errorMapper: 'errorInput -> 'errorOutput) - ([] input: CancellableTaskValidation<'ok, 'errorInput>) - : CancellableTaskValidation<'ok, 'errorOutput> = - cancellableTask { - let! input = input - return Result.mapError (List.map errorMapper) input - } + type CancellableTaskValidationBuilder with - let inline mapErrors - ([] errorMapper: 'errorInput list -> 'errorOutput list) - ([] input: CancellableTaskValidation<'ok, 'errorInput>) - : CancellableTaskValidation<'ok, 'errorOutput> = - cancellableTask { - let! input = input - return Result.mapError errorMapper input - } + [] + member inline this.MergeSources(left: 'Awaiter1, right: 'Awaiter2) = + this.Source( + // cancellableTask.Run( + // cancellableTask.Bind( + // (fun ct -> cancellableTask.Source(ValueTask<_> ct)), + // fun ct -> + // (cancellableTask.Bind( + // left, + // fun leftR -> + // cancellableTask.BindReturn( + // right, + // (fun rightR -> Validation.zip (Ok leftR) rightR) + // ) + // )) + // ) + // ) + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip (Ok l1) r1 + } + ) - /// Allows chaining of CancellableTaskValidation. - /// The continuation. - /// The value. - /// The result of the mapper wrapped in a CancellableTaskValidation. - let inline map - ([] mapper: 'input -> 'output) - ([] cTask: CancellableTaskValidation<'input, 'error>) - : CancellableTaskValidation<'output, 'error> = - cancellableTask { - let! cResult = cTask - return Result.map mapper cResult - } +[] +module CTVMergeSourcesExtensionsTV1TV2 = - /// Allows chaining of CancellableTaskValidation. - /// The continuation. - /// The 1st value. - /// The 2nd value. - /// The result of the mapper wrapped in a CancellableTaskValidation. - let inline map2 - ([] mapper: 'input1 -> 'input2 -> 'output) - ([] cTask1: CancellableTaskValidation<'input1, 'error>) - ([] cTask2: CancellableTaskValidation<'input2, 'error>) - : CancellableTaskValidation<'output, 'error> = - cancellableTask { - let! cResult1 = cTask1 - let! cResult2 = cTask2 - - return - match cResult1, cResult2 with - | Ok x, Ok y -> Ok(mapper x y) - | Ok _, Error errs -> Error errs - | Error errs, Ok _ -> Error errs - | Error errs1, Error errs2 -> - Error( - errs1 - @ errs2 - ) - } + type CancellableTaskValidationBuilder with - /// Allows chaining of CancellableTaskValidation. - /// The continuation. - /// The 1st value. - /// The 2nd value. - /// The 2nd value. - /// The result of the mapper wrapped in a CancellableTaskValidation. - let inline map3 - ([] mapper: 'input1 -> 'input2 -> 'input3 -> 'output) - ([] cTask1: CancellableTaskValidation<'input1, 'error>) - ([] cTask2: CancellableTaskValidation<'input2, 'error>) - ([] cTask3: CancellableTaskValidation<'input3, 'error>) - : CancellableTaskValidation<'output, 'error> = - cancellableTask { - let! cResult1 = cTask1 - let! cResult2 = cTask2 - let! cResult3 = cTask3 - - return - match cResult1, cResult2, cResult3 with - | Ok x, Ok y, Ok z -> Ok(mapper x y z) - | Error errs, Ok _, Ok _ -> Error errs - | Ok _, Error errs, Ok _ -> Error errs - | Ok _, Ok _, Error errs -> Error errs - | Error errs1, Error errs2, Ok _ -> - Error( - errs1 - @ errs2 - ) - | Ok _, Error errs1, Error errs2 -> - Error( - errs1 - @ errs2 - ) - | Error errs1, Ok _, Error errs2 -> - Error( - errs1 - @ errs2 - ) - | Error errs1, Error errs2, Error errs3 -> - Error( - errs1 - @ errs2 - @ errs3 - ) - } + [] + member inline this.MergeSources(left: 'Awaiter1, right: 'Awaiter2) = + this.Source( + cancellableTask { + let! struct (l1, r1) = cancellableTask.MergeSources(left, right) + return Validation.zip l1 r1 + } + ) - /// Allows chaining of CancellableTaskValidation. - /// A function wrapped in a CancellableTaskValidation - /// The value. - /// The result of the applicable. - let inline apply - ([] applicable: CancellableTaskValidation<'input -> 'output, 'error>) - ([] cTask: CancellableTaskValidation<'input, 'error>) - : CancellableTaskValidation<'output, 'error> = - cancellableTask { - let! applier = applicable - let! cResult = cTask - - return - match applier, cResult with - | Ok f, Ok x -> Ok(f x) - | Error errs, Ok _ - | Ok _, Error errs -> Error errs - | Error errs1, Error errs2 -> - Error( - errs1 - @ errs2 - ) - } +[] +module CancellableTaskResultBuilderPriority1 = + open System.Threading.Tasks - let inline orElse - ([] ifError: CancellableTaskValidation<'input, 'errorOutput>) - ([] cTask: CancellableTaskValidation<'input, 'errorInput>) - : CancellableTaskValidation<'input, 'errorOutput> = - cancellableTask { - let! result = cTask + type CancellableTaskValidationBuilder with - return! - result - |> Result.either ok (fun _ -> ifError) - } + member inline this.Source(result: Result<'T, 'Error>) = + this.Source(ValueTask<_>(Validation.ofResult result)) - let inline orElseWith - ([] ifErrorFunc: - 'errorInput list -> CancellableTaskValidation<'input, 'errorOutput>) - ([] cTask: CancellableTaskValidation<'input, 'errorInput>) - : CancellableTaskValidation<'input, 'errorOutput> = - cancellableTask { - let! result = cTask - return! - match result with - | Ok x -> ok x - | Error err -> ifErrorFunc err - } + member inline this.Source(choice: Choice<'T, 'Error>) = + this.Source(ValueTask<_>(Validation.ofChoice choice)) - /// Takes two CancellableTaskValidation, starts them serially in order of left to right, and returns a tuple of the pair. - /// The left value. - /// The right value. - /// A tuple of the parameters passed in - let inline zip - ([] left: CancellableTaskValidation<'left, 'error>) - ([] right: CancellableTaskValidation<'right, 'error>) - : CancellableTaskValidation<'left * 'right, 'error> = - cancellableTask { - let! r1 = left - let! r2 = right - - return Validation.zip r1 r2 - } - /// Takes two CancellableTaskValidation, starts them concurrently, and returns a tuple of the pair. - /// The left value. - /// The right value. - /// A tuple of the parameters passed in. - let inline parallelZip - ([] left: CancellableTaskValidation<'left, 'error>) - ([] right: CancellableTaskValidation<'right, 'error>) - : CancellableTaskValidation<'left * 'right, 'error> = - cancellableTask { - let! ct = CancellableTask.getCancellationToken () - let left = left ct - let right = right ct - let! r1 = left - let! r2 = right - - return Validation.zip r1 r2 +[] +module CancellableTaskResultBuilderPriority3 = + open System.Threading.Tasks - } + type CancellableTaskValidationBuilder with - // What's going on here? - // - // F# method overload resolution has some weird quirks we're taking advantage of to allow - // for binding (`let!/do!/return!`) many various types (Such as Task/Async/Result/Validation) - // in a computation expression. .The gist is, any member methods attached to the type itself - // (the Builder object) will be preferred above all else when selection overloads to resolve. It - // will then use the the most recent Extension Methods that have been opened. The way we structure - // these overloads is to provide the most "concrete" overloads first, and then the more generic - // ones later. For example, `Validation` is defined as a `Result<'T, 'Error list>`, but we also - // want to be able to bind to `Result` itself and create a list of errors from it. So we need to - // have a `Validation` member method in a higher module, and then a `Result` member method - // somewhere lower. Another example is `Task>` vs `Task<'T>`. We want to be able - // to bind to both, so we need to have a `Task>` member method in a higher - // module, and then a `Task<'T>` member method somewhere lower. - - // NoEagerConstraintApplication also changes behavior of SRTP methods, read the - // TaskBuilder RFC for more info. - - // The reason we do AutoOpens here instead of using the attribute on the module itself - // is because it may restrict how the implementation is relying on other sections, such as - // The MediumPriority module may use something from the HighPriority module. If we put the - // HighPriority module after the MediumPriority module it will fail to compile. So we don't want - // the order of the code itself to determine the priority, this allows us to control that ordering - // more explicitly. - // - // Additional readings: - // - [F# Computation Expression Method Overload Resolution Ordering](https://gist.github.com/TheAngryByrd/c8b9c8ebcda3bb162f425bfb281d2e2b) - // - [F# RFC FS-1097 - Task builder](https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1097-task-builder.md#feature-noeagerconstraintapplicationattribute) - // - ["Most concrete" tiebreaker for generic overloads](https://github.com/fsharp/fslang-suggestions/issues/905) - - - [] - [] - [] - [] - [] - [] - [] - [] - do () + member inline this.Source(result: Validation<'T, 'Error>) = + this.Source(ValueTask<_>(result)) diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/FsToolkit.ErrorHandling.IcedTasks.fsproj b/src/FsToolkit.ErrorHandling.IcedTasks/FsToolkit.ErrorHandling.IcedTasks.fsproj index a06ce42a..9012c923 100644 --- a/src/FsToolkit.ErrorHandling.IcedTasks/FsToolkit.ErrorHandling.IcedTasks.fsproj +++ b/src/FsToolkit.ErrorHandling.IcedTasks/FsToolkit.ErrorHandling.IcedTasks.fsproj @@ -1,21 +1,22 @@  - - Library - netstandard2.1 - preview - portable - FS3511;FS3513 - - - - - - - - - - - - - \ No newline at end of file + + Library + net6.0;netstandard2.0;netstandard2.1 + preview + portable + FS3511;FS3513 + + + + + + + + + + + + + diff --git a/src/FsToolkit.ErrorHandling.IcedTasks/paket.references b/src/FsToolkit.ErrorHandling.IcedTasks/paket.references index 992c1aac..1d1df93b 100644 --- a/src/FsToolkit.ErrorHandling.IcedTasks/paket.references +++ b/src/FsToolkit.ErrorHandling.IcedTasks/paket.references @@ -1,6 +1,5 @@ Microsoft.SourceLink.GitHub - -group NetStandard2_1 - FSharp.Core - IcedTasks \ No newline at end of file +FSharp.Core +IcedTasks +Microsoft.Bcl.AsyncInterfaces diff --git a/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj b/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj index 9a1f41bd..2239954e 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj +++ b/src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj @@ -1,28 +1,28 @@  - - Library - netstandard2.1;netstandard2.0 - portable - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + Library + netstandard2.1;netstandard2.0 + portable + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobOptionCE.fs b/src/FsToolkit.ErrorHandling.JobResult/JobOptionCE.fs index e7c15f5a..c459e84b 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/JobOptionCE.fs +++ b/src/FsToolkit.ErrorHandling.JobResult/JobOptionCE.fs @@ -118,19 +118,6 @@ module JobOptionCE = /// member inline _.Source(job: Job<_ option>) : Job<_ option> = job - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(async: Async<_ option>) : Job<_ option> = - async - |> Job.fromAsync - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: Task<_ option>) : Job<_ option> = - task - |> Job.awaitTask let jobOption = JobOptionBuilder() @@ -173,3 +160,24 @@ module JobOptionCEExtensions = a |> Job.awaitTask |> Job.map Some + +[] +// Having members as extensions gives them lower priority in +// overload resolution and allows skipping more type annotations. +module JobOptionCEExtensions2 = + + type JobOptionBuilder with + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(async: Async<_ option>) : Job<_ option> = + async + |> Job.fromAsync + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(task: Task<_ option>) : Job<_ option> = + task + |> Job.awaitTask diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobResultCE.fs b/src/FsToolkit.ErrorHandling.JobResult/JobResultCE.fs index d81191f0..f13dad76 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/JobResultCE.fs +++ b/src/FsToolkit.ErrorHandling.JobResult/JobResultCE.fs @@ -123,20 +123,6 @@ module JobResultCE = /// member inline _.Source(job': Job>) : Job> = job' - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// - member inline _.Source(task: Task>) : Job> = - task - |> Job.awaitTask - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(result: Async>) : Job> = - result - |> Job.fromAsync - let jobResult = JobResultBuilder() [] @@ -194,3 +180,22 @@ module JobResultCEExtensions = t |> Job.awaitUnitTask |> Job.map Ok + + +[] +module JobResultCEExtensions2 = + type JobResultBuilder with + + /// + /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. + /// + member inline _.Source(task: Task>) : Job> = + task + |> Job.awaitTask + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(result: Async>) : Job> = + result + |> Job.fromAsync diff --git a/src/FsToolkit.ErrorHandling.JobResult/paket.references b/src/FsToolkit.ErrorHandling.JobResult/paket.references index 5646e552..aceb1c1e 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/paket.references +++ b/src/FsToolkit.ErrorHandling.JobResult/paket.references @@ -1,6 +1,4 @@ Microsoft.SourceLink.GitHub - -group NetStandard2 - Hopac -group NetStandard2_1 - Hopac \ No newline at end of file +FSharp.Core +Hopac +Microsoft.Bcl.AsyncInterfaces diff --git a/src/FsToolkit.ErrorHandling.TaskResult/AssemblyInfo.fs b/src/FsToolkit.ErrorHandling.TaskResult/AssemblyInfo.fs deleted file mode 100644 index f5229e4a..00000000 --- a/src/FsToolkit.ErrorHandling.TaskResult/AssemblyInfo.fs +++ /dev/null @@ -1,19 +0,0 @@ -// Auto-Generated by FAKE; do not edit -namespace System -open System.Reflection - -[] -[] -[] -[] -[] -[] -do () - -module internal AssemblyVersionInformation = - let [] AssemblyTitle = "FsToolkit.ErrorHandling.TaskResult" - let [] AssemblyProduct = "FsToolkit.ErrorHandling" - let [] AssemblyDescription = "FsToolkit.ErrorHandling is a utility library to work with the Result type in F#, and allows you to do clear, simple and powerful error handling." - let [] AssemblyVersion = "4.18.0" - let [] AssemblyFileVersion = "4.18.0" - let [] AssemblyConfiguration = "Release" diff --git a/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj b/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj deleted file mode 100644 index 751f1117..00000000 --- a/src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - Library - netstandard2.1;netstandard2.0 - - portable - preview - FS1204;FS3511;FS3513 - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/FsToolkit.ErrorHandling.TaskResult/List.fs b/src/FsToolkit.ErrorHandling.TaskResult/List.fs deleted file mode 100644 index 275659c4..00000000 --- a/src/FsToolkit.ErrorHandling.TaskResult/List.fs +++ /dev/null @@ -1,64 +0,0 @@ -namespace FsToolkit.ErrorHandling - -open System.Threading.Tasks -open FsToolkit.ErrorHandling -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine -#endif - -[] -module List = - let private traverseTaskResultM' (f: 'c -> Task>) (xs: 'c list) = - let mutable state = Ok [] - let mutable index = 0 - - let xs = - xs - |> List.toArray - - task { - while state - |> Result.isOk - && index < xs.Length do - let! r = - xs - |> Array.item index - |> f - - index <- index + 1 - - match (r, state) with - | Ok y, Ok ys -> state <- Ok(y :: ys) - | Error e, _ -> state <- Error e - | _, _ -> () - - return - state - |> Result.map List.rev - } - - let traverseTaskResultM f xs = traverseTaskResultM' f xs - - let sequenceTaskResultM xs = traverseTaskResultM id xs - - let private traverseTaskResultA' (f: 'c -> Task>) (xs: 'c list) = - let mutable state = Ok [] - - task { - for x in xs do - let! r = f x - - match (r, state) with - | Ok y, Ok ys -> state <- Ok(y :: ys) - | Error e, Error errs -> state <- Error(e :: errs) - | Ok _, Error e -> state <- Error e - | Error e, Ok _ -> state <- Error [ e ] - - return - state - |> Result.eitherMap List.rev List.rev - } - - let traverseTaskResultA f xs = traverseTaskResultA' f xs - - let sequenceTaskResultA xs = traverseTaskResultA id xs diff --git a/src/FsToolkit.ErrorHandling.TaskResult/Result.fs b/src/FsToolkit.ErrorHandling.TaskResult/Result.fs deleted file mode 100644 index 68827ed0..00000000 --- a/src/FsToolkit.ErrorHandling.TaskResult/Result.fs +++ /dev/null @@ -1,17 +0,0 @@ -namespace FsToolkit.ErrorHandling - -open System.Threading.Tasks -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine -#endif - -module Result = - - let sequenceTask (resTask: Result, 'b>) : Task> = - task { - match resTask with - | Ok task -> - let! x = task - return Ok x - | Error err -> return Error err - } diff --git a/src/FsToolkit.ErrorHandling.TaskResult/paket.references b/src/FsToolkit.ErrorHandling.TaskResult/paket.references deleted file mode 100644 index 2d9b38d1..00000000 --- a/src/FsToolkit.ErrorHandling.TaskResult/paket.references +++ /dev/null @@ -1,4 +0,0 @@ -Microsoft.SourceLink.GitHub - -group NetStandard2 - Ply \ No newline at end of file diff --git a/src/FsToolkit.ErrorHandling/AsyncOptionCE.fs b/src/FsToolkit.ErrorHandling/AsyncOptionCE.fs index 0583eac4..ccec9801 100644 --- a/src/FsToolkit.ErrorHandling/AsyncOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/AsyncOptionCE.fs @@ -45,10 +45,7 @@ module AsyncOptionCE = [] compensation: unit -> unit ) : Async<'value option> = async.TryFinally(computation, compensation) - - -#if NETSTANDARD2_1 - +#if !FABLE_COMPILER member inline _.TryFinallyAsync ( computation: Async<'value option>, @@ -103,15 +100,6 @@ module AsyncOptionCE = /// member inline _.Source(async: Async<'value option>) : Async<'value option> = async -#if !FABLE_COMPILER - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: Task<'value option>) : Async<'value option> = - task - |> Async.AwaitTask - -#endif let asyncOption = AsyncOptionBuilder() @@ -180,4 +168,17 @@ module AsyncOptionCEExtensions = a |> Async.AwaitTask |> Async.map Some + +[] +module AsyncOptionCEExtensionsHigher = + + type AsyncOptionBuilder with + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(task: Task<'value option>) : Async<'value option> = + task + |> Async.AwaitTask + #endif diff --git a/src/FsToolkit.ErrorHandling/AsyncResultCE.fs b/src/FsToolkit.ErrorHandling/AsyncResultCE.fs index 0529c48f..6116b3da 100644 --- a/src/FsToolkit.ErrorHandling/AsyncResultCE.fs +++ b/src/FsToolkit.ErrorHandling/AsyncResultCE.fs @@ -53,9 +53,7 @@ module AsyncResultCE = [] compensation: unit -> unit ) : Async> = async.TryFinally(computation, compensation) - -#if NETSTANDARD2_1 - +#if !FABLE_COMPILER member inline _.TryFinallyAsync ( computation: Async>, @@ -91,8 +89,6 @@ module AsyncResultCE = ) ) #endif - - member inline this.While ( [] guard: unit -> bool, @@ -116,14 +112,6 @@ module AsyncResultCE = ) : Async> = AsyncResult.map f x - member inline _.MergeSources - ( - t1: Async>, - t2: Async> - ) : Async> = - AsyncResult.zip t1 t2 - - /// /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. /// @@ -132,14 +120,6 @@ module AsyncResultCE = member inline _.Source(result: Async>) : Async> = result -#if !FABLE_COMPILER - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: Task>) : Async> = - task - |> Async.AwaitTask -#endif let asyncResult = AsyncResultBuilder() @@ -215,3 +195,17 @@ module AsyncResultCEExtensions = |> Async.AwaitTask |> Async.map Ok #endif + +#if !FABLE_COMPILER +[] +module AsyncResultCEExtensions2 = + + type AsyncResultBuilder with + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(task: Task>) : Async> = + task + |> Async.AwaitTask +#endif diff --git a/src/FsToolkit.ErrorHandling/AsyncResultOptionCE.fs b/src/FsToolkit.ErrorHandling/AsyncResultOptionCE.fs index b7e07b9a..3f6fbc28 100644 --- a/src/FsToolkit.ErrorHandling/AsyncResultOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/AsyncResultOptionCE.fs @@ -43,10 +43,7 @@ module AsyncResultOptionCE = [] compensation: unit -> unit ) : AsyncResultOption<'ok, 'error> = async.TryFinally(computation, compensation) - - -#if NETSTANDARD2_1 - +#if !FABLE_COMPILER member inline _.TryFinallyAsync ( computation: AsyncResultOption<'ok, 'error>, @@ -66,7 +63,6 @@ module AsyncResultOptionCE = Async.TryFinallyAsync(computation, compensation) - member inline this.Using ( resource: 'ok :> IAsyncDisposable, @@ -83,7 +79,6 @@ module AsyncResultOptionCE = ) #endif - member inline this.While ( [] guard: unit -> bool, @@ -108,19 +103,7 @@ module AsyncResultOptionCE = (result: AsyncResultOption<'ok, 'error>) : AsyncResultOption<'ok, 'error> = result -#if !FABLE_COMPILER - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// - /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder - /// - member inline _.Source - (result: Task, 'error>>) - : AsyncResultOption<'ok, 'error> = - result - |> Async.AwaitTask -#endif let asyncResultOption = new AsyncResultOptionBuilder() @@ -236,3 +219,22 @@ module AsyncResultOptionCEExtensionsHighPriority = |> Async.AwaitTask |> AsyncResultOption.ofAsyncOption #endif + +#if !FABLE_COMPILER +[] +module AsyncResultOptionCEExtensionsHighPriority2 = + + type AsyncResultOptionBuilder with + + + /// + /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. + /// + /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder + /// + member inline _.Source + (result: Task, 'error>>) + : AsyncResultOption<'ok, 'error> = + result + |> Async.AwaitTask +#endif diff --git a/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj b/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj index 86409b09..68d3fff2 100644 --- a/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj +++ b/src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj @@ -1,52 +1,68 @@ - - - Library - netstandard2.1;netstandard2.0 - preview - portable - - $(PackageTags), fable-library, fable-dotnet, fable-javascript, fable-python - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Library + netstandard2.1;netstandard2.0 + preview + portable + FS1204;FS3511;FS3513 + $(PackageTags), fable-library, fable-dotnet, fable-javascript, fable-python + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FsToolkit.ErrorHandling/List.fs b/src/FsToolkit.ErrorHandling/List.fs index 41ec5496..f3401c17 100644 --- a/src/FsToolkit.ErrorHandling/List.fs +++ b/src/FsToolkit.ErrorHandling/List.fs @@ -215,4 +215,63 @@ module List = /// A representing the sequence of results. let sequenceVOptionM xs = traverseVOptionM id xs + + open System.Threading.Tasks + + let private traverseTaskResultM' (f: 'c -> Task>) (xs: 'c list) = + let mutable state = Ok [] + let mutable index = 0 + + let xs = + xs + |> List.toArray + + task { + while state + |> Result.isOk + && index < xs.Length do + let! r = + xs + |> Array.item index + |> f + + index <- index + 1 + + match (r, state) with + | Ok y, Ok ys -> state <- Ok(y :: ys) + | Error e, _ -> state <- Error e + | _, _ -> () + + return + state + |> Result.map List.rev + } + + let traverseTaskResultM f xs = traverseTaskResultM' f xs + + let sequenceTaskResultM xs = traverseTaskResultM id xs + + let private traverseTaskResultA' (f: 'c -> Task>) (xs: 'c list) = + let mutable state = Ok [] + + task { + for x in xs do + let! r = f x + + match (r, state) with + | Ok y, Ok ys -> state <- Ok(y :: ys) + | Error e, Error errs -> state <- Error(e :: errs) + | Ok _, Error e -> state <- Error e + | Error e, Ok _ -> state <- Error [ e ] + + return + state + |> Result.eitherMap List.rev List.rev + } + + let traverseTaskResultA f xs = traverseTaskResultA' f xs + + let sequenceTaskResultA xs = traverseTaskResultA id xs + + #endif diff --git a/src/FsToolkit.ErrorHandling/OptionCE.fs b/src/FsToolkit.ErrorHandling/OptionCE.fs index 29dd8e0b..cf6ec296 100644 --- a/src/FsToolkit.ErrorHandling/OptionCE.fs +++ b/src/FsToolkit.ErrorHandling/OptionCE.fs @@ -111,13 +111,6 @@ module OptionCE = ) : 'output option = Option.map f (Option.ofObj x) - member inline _.MergeSources - ( - option1: 'left option, - option2: 'right option - ) : ('left * 'right) option = - Option.zip option1 option2 - /// /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. /// @@ -125,12 +118,6 @@ module OptionCE = /// member inline _.Source(result: 'value option) : 'value option = result - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(vopt: 'value voption) : 'value option = Option.ofValueOption vopt - /// /// The default instance of the `OptionBuilder` type. /// @@ -145,29 +132,6 @@ module OptionExtensionsLower = member inline _.Source(m: string) : string option = Option.ofObj m - member inline _.MergeSources - ( - nullableObj1: 'left, - option2: 'right option - ) : ('left * 'right) option = - Option.zip (Option.ofObj nullableObj1) option2 - - - member inline _.MergeSources - ( - option1: 'left option, - nullableObj2: 'right - ) : ('left * 'right) option = - Option.zip (option1) (Option.ofObj nullableObj2) - - - member inline _.MergeSources - ( - nullableObj1: 'left, - nullableObj2: 'right - ) : ('left * 'right) option = - Option.zip (Option.ofObj nullableObj1) (Option.ofObj nullableObj2) - [] module OptionExtensions = open System @@ -184,3 +148,8 @@ module OptionExtensions = /// member inline _.Source(nullable: Nullable<'value>) : 'value option = Option.ofNullable nullable + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(vopt: 'value voption) : 'value option = Option.ofValueOption vopt diff --git a/src/FsToolkit.ErrorHandling/Result.fs b/src/FsToolkit.ErrorHandling/Result.fs index 406300d0..8c00d2d5 100644 --- a/src/FsToolkit.ErrorHandling/Result.fs +++ b/src/FsToolkit.ErrorHandling/Result.fs @@ -1,5 +1,6 @@ namespace FsToolkit.ErrorHandling + /// /// Helper functions for working with Result values. /// @@ -595,6 +596,19 @@ module Result = : Async> = sequenceAsync ((map f) res) +#if !FABLE_COMPILER + open System.Threading.Tasks + + /// Converts a Result,_> to an Async> + let sequenceTask (resTask: Result, 'b>) : Task> = + task { + match resTask with + | Ok task -> + let! x = task + return Ok x + | Error err -> return Error err + } +#endif /// /// Returns the Ok value or runs the specified function over the error value. diff --git a/src/FsToolkit.ErrorHandling/ResultCE.fs b/src/FsToolkit.ErrorHandling/ResultCE.fs index 9ef5afb6..e1b43386 100644 --- a/src/FsToolkit.ErrorHandling/ResultCE.fs +++ b/src/FsToolkit.ErrorHandling/ResultCE.fs @@ -109,13 +109,6 @@ module ResultCE = ) : Result<'okOutput, 'error> = Result.map f x - member inline _.MergeSources - ( - left: Result<'left, 'error>, - right: Result<'right, 'error> - ) : Result<'left * 'right, 'error> = - Result.zip left right - /// /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. /// diff --git a/src/FsToolkit.ErrorHandling/ResultOptionCE.fs b/src/FsToolkit.ErrorHandling/ResultOptionCE.fs index 60913fc1..60b9db0f 100644 --- a/src/FsToolkit.ErrorHandling/ResultOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/ResultOptionCE.fs @@ -114,13 +114,6 @@ module ResultOptionCE = ) : Result<'U option, 'TError> = ResultOption.map binder resultOpt - member inline _.MergeSources - ( - left: Result<'left option, 'error>, - right: Result<'right option, 'error> - ) : Result<('left * 'right) option, 'error> = - ResultOption.zip left right - member inline _.Source(result: Result<'ok option, 'error>) : Result<'ok option, 'error> = result diff --git a/src/FsToolkit.ErrorHandling/Seq.fs b/src/FsToolkit.ErrorHandling/Seq.fs index 89d47916..9cee77a4 100644 --- a/src/FsToolkit.ErrorHandling/Seq.fs +++ b/src/FsToolkit.ErrorHandling/Seq.fs @@ -1,7 +1,5 @@ -namespace FsToolkit.ErrorHandling - [] -module Seq = +module FsToolkit.ErrorHandling.Seq /// /// Applies a function to each element of a sequence and returns a single result diff --git a/src/FsToolkit.ErrorHandling/Shims.fs b/src/FsToolkit.ErrorHandling/Shims.fs deleted file mode 100644 index b7d0c719..00000000 --- a/src/FsToolkit.ErrorHandling/Shims.fs +++ /dev/null @@ -1,22 +0,0 @@ -namespace FsToolkit.ErrorHandling - - -#if NETSTANDARD2_0 -open System - -/// InlineIfLambda doesn't exist until FSharp.Core 6.0. -/// Since we're targeting netstandard2.0 with FSharp.Core 4.7 to keep this libraries' reach -/// we need to create a fake attribute that does nothing instead of having ifdefs in each function argument -[] -[] -type internal InlineIfLambdaAttribute() = - inherit System.Attribute() - -open System.Runtime.CompilerServices - -// Let all the child libraries have access to this shim as well -[] -[] -[] -do () -#endif diff --git a/src/FsToolkit.ErrorHandling.TaskResult/Task.fs b/src/FsToolkit.ErrorHandling/Task.fs similarity index 96% rename from src/FsToolkit.ErrorHandling.TaskResult/Task.fs rename to src/FsToolkit.ErrorHandling/Task.fs index d953fc2f..fb5dfb07 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/Task.fs +++ b/src/FsToolkit.ErrorHandling/Task.fs @@ -1,10 +1,7 @@ namespace FsToolkit.ErrorHandling -open System.Threading.Tasks -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine -#endif +open System.Threading.Tasks [] module Task = @@ -18,6 +15,7 @@ module Task = return! f x } + let inline bindV ([] f: 'a -> Task<'b>) (x: ValueTask<'a>) = task { let! x = x diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOp.fs b/src/FsToolkit.ErrorHandling/TaskOp.fs similarity index 100% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskOp.fs rename to src/FsToolkit.ErrorHandling/TaskOp.fs diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs b/src/FsToolkit.ErrorHandling/TaskOption.fs similarity index 98% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs rename to src/FsToolkit.ErrorHandling/TaskOption.fs index a154a71c..f3a30649 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskOption.fs +++ b/src/FsToolkit.ErrorHandling/TaskOption.fs @@ -1,9 +1,7 @@ namespace FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine -#endif + [] module TaskOption = diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionCE.fs b/src/FsToolkit.ErrorHandling/TaskOptionCE.fs similarity index 60% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskOptionCE.fs rename to src/FsToolkit.ErrorHandling/TaskOptionCE.fs index 9bd7ee9b..69e59823 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/TaskOptionCE.fs @@ -4,431 +4,6 @@ open System open System.Threading.Tasks -#if NETSTANDARD2_0 -open Ply -open System.Runtime.CompilerServices - -[] -module TaskOptionCE = - type TaskOptionBuilder() = - member val SomeUnit = Some() - - member inline _.Return(value: 'T) : Ply<_ option> = - option.Return value - |> FSharp.Control.Tasks.Affine.Unsafe.uply.Return - - member inline _.ReturnFrom(taskResult: Task<_ option>) : Ply<_ option> = - FSharp.Control.Tasks.Affine.Unsafe.uply.ReturnFrom taskResult - - member inline _.Zero() : Ply<_ option> = - option.Zero() - |> FSharp.Control.Tasks.Affine.Unsafe.uply.Return - - member inline _.Bind - ( - taskResult: Task<_ option>, - [] binder: 'T -> Ply<_ option> - ) : Ply<_ option> = - let binder' r = - match r with - | Some x -> binder x - | None -> FSharp.Control.Tasks.Affine.Unsafe.uply.Return None - - FSharp.Control.Tasks.Affine.Unsafe.uply.Bind(taskResult, binder') - - member inline _.Delay([] generator: unit -> Ply<_ option>) = - FSharp.Control.Tasks.Affine.Unsafe.uply.Delay(generator) - - member inline _.Combine - ( - computation1: Ply<'T option>, - [] computation2: unit -> Ply<'U option> - ) : Ply<'U option> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - match! computation1 with - | None -> return None - | Some _ -> return! computation2 () - } - - member inline _.TryWith - ( - [] computation: unit -> Ply<_ option>, - [] handler: exn -> Ply<_ option> - ) : Ply<_ option> = - FSharp.Control.Tasks.Affine.Unsafe.uply.TryWith(computation, handler) - - member inline _.TryFinally - ( - [] computation: unit -> Ply<_ option>, - [] compensation: unit -> unit - ) : Ply<_ option> = - FSharp.Control.Tasks.Affine.Unsafe.uply.TryFinally(computation, compensation) - - member inline _.Using - ( - resource: 'T :> IDisposable, - [] binder: 'T -> Ply<_ option> - ) : Ply<_ option> = - FSharp.Control.Tasks.Affine.Unsafe.uply.Using(resource, binder) - - member inline _.While - ( - [] guard: unit -> bool, - [] computation: unit -> Ply<'U option> - ) : Ply<'U option> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - let mutable fin, result = false, None - - while not fin - && guard () do - match! computation () with - | Some _ as o -> result <- o - | None -> - result <- None - fin <- true - - return result - } - - member inline _.For(sequence: #seq<'T>, binder: 'T -> Ply<'U option>) : Ply<'U option> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - use enumerator = sequence.GetEnumerator() - let mutable fin, result = false, None - - while not fin - && enumerator.MoveNext() do - match! binder enumerator.Current with - | Some _ as o -> result <- o - | None -> - result <- None - fin <- true - - return result - } - - member inline this.BindReturn(x: Task<'T option>, [] f) = - this.Bind(x, (fun x -> this.Return(f x))) - - member inline _.MergeSources(t1: Task<'T option>, t2: Task<'T1 option>) = - TaskOption.zip t1 t2 - - member inline _.Run([] f: unit -> Ply<'m>) = - FSharp.Control.Tasks.Affine.task.Run f - - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder - /// - member inline _.Source(task: Task<_ option>) : Task<_ option> = task - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask<_ option>) : Task<_ option> = - FSharp.Control.Tasks.Affine.task { return! t } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(async: Async<_ option>) : Task<_ option> = - async - |> Async.StartImmediateAsTask - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply<_ option>) : Task<_ option> = - FSharp.Control.Tasks.Affine.task { return! p } - - let taskOption = TaskOptionBuilder() - - type BackgroundTaskOptionBuilder() = - member val SomeUnit = Some() - - member inline _.Return(value: 'T) : Ply<_ option> = - option.Return value - |> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return - - member inline _.ReturnFrom(taskResult: Task<_ option>) : Ply<_ option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.ReturnFrom taskResult - - member inline _.Zero() : Ply<_ option> = - option.Zero() - |> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return - - member inline _.Bind - ( - taskResult: Task<_ option>, - [] binder: 'T -> Ply<_ option> - ) : Ply<_ option> = - let binder' r = - match r with - | Some x -> binder x - | None -> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return None - - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Bind(taskResult, binder') - - member inline _.Delay([] generator: unit -> Ply<_ option>) = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Delay(generator) - - member inline _.Combine - ( - computation1: Ply<'T option>, - [] computation2: unit -> Ply<'U option> - ) : Ply<'U option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - match! computation1 with - | None -> return None - | Some _ -> return! computation2 () - } - - member inline _.TryWith - ( - [] computation: unit -> Ply<_ option>, - [] handler: exn -> Ply<_ option> - ) : Ply<_ option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryWith(computation, handler) - - member inline _.TryFinally - ( - [] computation: unit -> Ply<_ option>, - [] compensation: unit -> unit - ) : Ply<_ option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryFinally(computation, compensation) - - member inline _.Using - ( - resource: 'T :> IDisposable, - [] binder: 'T -> Ply<_ option> - ) : Ply<_ option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Using(resource, binder) - - member inline _.While - ( - [] guard: unit -> bool, - [] computation: unit -> Ply<'U option> - ) : Ply<'U option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - let mutable fin, result = false, None - - while not fin - && guard () do - match! computation () with - | Some _ as o -> result <- o - | None -> - result <- None - fin <- true - - return result - } - - member inline _.For(sequence: #seq<'T>, binder: 'T -> Ply<'U option>) : Ply<'U option> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - use enumerator = sequence.GetEnumerator() - let mutable fin, result = false, None - - while not fin - && enumerator.MoveNext() do - match! binder enumerator.Current with - | Some _ as o -> result <- o - | None -> - result <- None - fin <- true - - return result - } - - member inline this.BindReturn(x: Task<'T option>, [] f) = - this.Bind(x, (fun x -> this.Return(f x))) - - member inline _.MergeSources(t1: Task<'T option>, t2: Task<'T1 option>) = - FSharp.Control.Tasks.NonAffine.task { - let! o1 = t1 - let! o2 = t2 - return Option.zip o1 o2 - } - - member inline _.Run([] f: unit -> Ply<'m>) = - FSharp.Control.Tasks.NonAffine.task.Run f - - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder - /// - member inline _.Source(task: Task<_ option>) : Task<_ option> = task - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask<_ option>) : Task<_ option> = - FSharp.Control.Tasks.NonAffine.task { return! t } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(async: Async<_ option>) : Task<_ option> = - async - |> Async.StartImmediateAsTask - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply<_ option>) : Task<_ option> = - FSharp.Control.Tasks.NonAffine.task { return! p } - - let backgroundTaskOption = BackgroundTaskOptionBuilder() - - -[] -// Having members as extensions gives them lower priority in -// overload resolution and allows skipping more type annotations. -module TaskOptionCEExtensionsLower = - - type TaskOptionBuilder with - - member inline this.Source(t: ^TaskLike) : Task<'T option> = - FSharp.Control.Tasks.Affine.task { - let! r = t - return Some r - } - - type BackgroundTaskOptionBuilder with - - member inline this.Source(t: ^TaskLike) : Task<'T option> = - FSharp.Control.Tasks.NonAffine.task { - let! r = t - return Some r - } - -[] -// Having members as extensions gives them lower priority in -// overload resolution and allows skipping more type annotations. -module TaskOptionCEExtensions = - - type TaskOptionBuilder with - - /// - /// Needed to allow `for..in` and `for..do` functionality - /// - member inline _.Source(s: #seq<_>) = s - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(r: 't option) = Task.singleton r - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: Task<'T>) = - FSharp.Control.Tasks.Affine.task { - let! o = a - return Some o - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline x.Source(a: Task) = - FSharp.Control.Tasks.Affine.task { - do! a - return x.SomeUnit - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: ValueTask<'T>) = - FSharp.Control.Tasks.Affine.task { - let! o = a - return Some o - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline x.Source(a: ValueTask) = - FSharp.Control.Tasks.Affine.task { - do! a - return x.SomeUnit - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: Async<'t>) = - FSharp.Control.Tasks.Affine.task { - let! o = - a - |> Async.StartImmediateAsTask - - return Some o - } - - - type BackgroundTaskOptionBuilder with - - /// - /// Needed to allow `for..in` and `for..do` functionality - /// - member inline _.Source(s: #seq<_>) = s - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(r: 't option) = Task.singleton r - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: Task<'T>) = - FSharp.Control.Tasks.NonAffine.task { - let! o = a - return Some o - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline x.Source(a: Task) = - FSharp.Control.Tasks.NonAffine.task { - do! a - return x.SomeUnit - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: ValueTask<'T>) = - FSharp.Control.Tasks.NonAffine.task { - let! o = a - return Some o - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline x.Source(a: ValueTask) = - FSharp.Control.Tasks.NonAffine.task { - do! a - return x.SomeUnit - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(a: Async<'t>) = - FSharp.Control.Tasks.NonAffine.task { - let! o = - a - |> Async.StartImmediateAsTask - - return Some o - } - - -#else - open System open System.Runtime.CompilerServices open System.Threading @@ -637,16 +212,8 @@ type TaskOptionBuilderBase() = ) ) - member inline this.Source(computation: Async<'T option>) : TaskOption<'T> = - computation - |> Async.StartImmediateAsTask - member inline this.Source(taskOption: TaskOption<'T>) : TaskOption<'T> = taskOption - member inline this.Source(taskOption: ValueTask<'T option>) : TaskOption<'T> = - taskOption.AsTask() - - type TaskOptionBuilder() = inherit TaskOptionBuilderBase() @@ -1043,4 +610,16 @@ module TaskOptionCEExtensionsMediumPriority = |> Async.map Some |> Async.StartImmediateAsTask -#endif + +[] +module TaskOptionCEExtensionsHighPriority2 = + + // Medium priority extensions + type TaskOptionBuilderBase with + + member inline this.Source(computation: Async<'T option>) : TaskOption<'T> = + computation + |> Async.StartImmediateAsTask + + member inline this.Source(taskOption: ValueTask<'T option>) : TaskOption<'T> = + taskOption.AsTask() diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskOptionOp.fs b/src/FsToolkit.ErrorHandling/TaskOptionOp.fs similarity index 100% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskOptionOp.fs rename to src/FsToolkit.ErrorHandling/TaskOptionOp.fs diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResult.fs b/src/FsToolkit.ErrorHandling/TaskResult.fs similarity index 99% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResult.fs rename to src/FsToolkit.ErrorHandling/TaskResult.fs index fe42be3f..82b05e0b 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskResult.fs +++ b/src/FsToolkit.ErrorHandling/TaskResult.fs @@ -1,9 +1,6 @@ -namespace FsToolkit.ErrorHandling +namespace FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine -#endif [] module TaskResult = diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultCE.fs b/src/FsToolkit.ErrorHandling/TaskResultCE.fs similarity index 57% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResultCE.fs rename to src/FsToolkit.ErrorHandling/TaskResultCE.fs index ce024913..f0a87aa7 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultCE.fs +++ b/src/FsToolkit.ErrorHandling/TaskResultCE.fs @@ -1,484 +1,9 @@ -namespace FsToolkit.ErrorHandling +namespace FsToolkit.ErrorHandling open System open System.Threading.Tasks -#if NETSTANDARD2_0 -// open FSharp.Control.Tasks -open Ply - -[] -module TaskResultCE = - - type TaskResultBuilder() = - - member inline _.Return(value: 'T) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply.Return(result.Return value) - - member inline _.ReturnFrom - (taskResult: Task>) - : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply.ReturnFrom taskResult - - member inline _.Zero() : Ply> = - result.Zero() - |> FSharp.Control.Tasks.Affine.Unsafe.uply.Return - - member inline _.Bind - ( - taskResult: Task>, - [] binder: 'T -> Ply> - ) : Ply> = - let binder' r = - match r with - | Ok x -> binder x - | Error x -> - Error x - |> FSharp.Control.Tasks.Affine.Unsafe.uply.Return - - FSharp.Control.Tasks.Affine.Unsafe.uply.Bind(taskResult, binder') - - member inline _.Delay([] generator: unit -> Ply>) = - FSharp.Control.Tasks.Affine.Unsafe.uply.Delay(generator) - - member inline _.Combine - ( - computation1: Ply>, - [] computation2: unit -> Ply> - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - match! computation1 with - | Error e -> return Error e - | Ok _ -> return! computation2 () - } - - member inline _.TryWith - ( - [] computation: unit -> Ply>, - [] handler: exn -> Ply> - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply.TryWith(computation, handler) - - member inline _.TryFinally - ( - [] computation: unit -> Ply>, - [] compensation: unit -> unit - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply.TryFinally(computation, compensation) - - member inline _.Using - ( - resource: 'T :> IDisposable, - [] binder: 'T -> Ply> - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply.Using(resource, binder) - - member inline _.While - ( - [] guard: unit -> bool, - [] computation: unit -> Ply> - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - let mutable fin, result = false, Ok() - - while not fin - && guard () do - match! computation () with - | Ok x -> x - | Error _ as e -> - result <- e - fin <- true - - return result - } - - member inline _.For - ( - sequence: #seq<'T>, - [] binder: 'T -> Ply> - ) : Ply> = - FSharp.Control.Tasks.Affine.Unsafe.uply { - use enumerator = sequence.GetEnumerator() - let mutable fin, result = false, Ok() - - while not fin - && enumerator.MoveNext() do - match! binder enumerator.Current with - | Ok x -> x - | Error _ as e -> - result <- e - fin <- true - - return result - } - - member inline this.BindReturn(x: Task>, [] f) = - this.Bind(x, (fun x -> this.Return(f x))) - - member inline _.MergeSources(t1: Task>, t2: Task>) = - TaskResult.zip t1 t2 - - member inline _.Run([] f: unit -> Ply<'m>) = - FSharp.Control.Tasks.Affine.task.Run f - - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// - /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder - /// - member inline _.Source(task: Task>) : Task> = task - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask>) : Task> = - FSharp.Control.Tasks.Affine.task { return! t } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(result: Async>) : Task> = - result - |> Async.StartImmediateAsTask - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply>) : Task> = - FSharp.Control.Tasks.Affine.task { return! p } - - let taskResult = TaskResultBuilder() - - - type BackgroundTaskResultBuilder() = - - member inline _.Return(value: 'T) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return(result.Return value) - - member inline _.ReturnFrom - (taskResult: Task>) - : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.ReturnFrom taskResult - - member inline _.Zero() : Ply> = - result.Zero() - |> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return - - - member inline _.Bind - ( - taskResult: Task>, - [] binder: 'T -> Ply> - ) : Ply> = - let binder' r = - match r with - | Ok x -> binder x - | Error x -> - Error x - |> FSharp.Control.Tasks.NonAffine.Unsafe.uply.Return - - - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Bind(taskResult, binder') - - member inline _.Delay([] generator: unit -> Ply>) = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Delay(generator) - - member inline _.Combine - ( - computation1: Ply>, - [] computation2: unit -> Ply> - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - match! computation1 with - | Error e -> return Error e - | Ok _ -> return! computation2 () - } - - member inline _.TryWith - ( - [] computation: unit -> Ply>, - [] handler: exn -> Ply> - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryWith(computation, handler) - - member inline _.TryFinally - ( - [] computation: unit -> Ply>, - [] compensation: unit -> unit - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.TryFinally(computation, compensation) - - member inline _.Using - ( - resource: 'T :> IDisposable, - [] binder: 'T -> Ply> - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply.Using(resource, binder) - - member inline _.While - ( - [] guard: unit -> bool, - [] computation: unit -> Ply> - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - let mutable fin, result = false, Ok() - - while not fin - && guard () do - match! computation () with - | Ok x -> x - | Error _ as e -> - result <- e - fin <- true - - return result - } - - member inline _.For - ( - sequence: #seq<'T>, - [] binder: 'T -> Ply> - ) : Ply> = - FSharp.Control.Tasks.NonAffine.Unsafe.uply { - use enumerator = sequence.GetEnumerator() - let mutable fin, result = false, Ok() - - while not fin - && enumerator.MoveNext() do - match! binder enumerator.Current with - | Ok x -> x - | Error _ as e -> - result <- e - fin <- true - - return result - } - - member inline this.BindReturn(x: Task>, [] f) = - this.Bind(x, (fun x -> this.Return(f x))) - - member inline _.MergeSources(t1: Task>, t2: Task>) = - FSharp.Control.Tasks.NonAffine.task { - let! r1 = t1 - let! r2 = t2 - return Result.zip r1 r2 - } - - member inline _.Run([] f: unit -> Ply<'m>) = - FSharp.Control.Tasks.NonAffine.task.Run f - - /// - /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. - /// - /// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder - /// - member inline _.Source(task: Task>) : Task> = task - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask>) : Task> = - FSharp.Control.Tasks.NonAffine.task { return! t } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(result: Async>) : Task> = - result - |> Async.StartImmediateAsTask - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply>) : Task> = - FSharp.Control.Tasks.NonAffine.task { return! p } - - - let backgroundTaskResult = BackgroundTaskResultBuilder() - -[] -// Having members as extensions gives them lower priority in -// overload resolution and allows skipping more type annotations. -module TaskResultCEExtensionsLower = - - type TaskResultBuilder with - - member inline this.Source(t: ^TaskLike) : Task> = - FSharp.Control.Tasks.Affine.task { - let! r = t - return Ok r - } - - type BackgroundTaskResultBuilder with - - member inline this.Source(t: ^TaskLike) : Task> = - FSharp.Control.Tasks.NonAffine.task { - let! r = t - return Ok r - } - -// Having members as extensions gives them lower priority in -// overload resolution between Task<_> and Task>. -[] -module TaskResultCEExtensions = - type TaskResultBuilder with - - /// - /// Needed to allow `for..in` and `for..do` functionality - /// - member inline _.Source(s: #seq<_>) = s - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(result: Result<_, _>) : Task> = Task.singleton result - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(choice: Choice<_, _>) : Task> = - choice - |> Result.ofChoice - |> Task.singleton - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(asyncComputation: Async<_>) : Task> = - FSharp.Control.Tasks.Affine.task { - let! r = - asyncComputation - |> Async.StartImmediateAsTask - - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: Task<_>) : Task> = - FSharp.Control.Tasks.Affine.task { - let! r = task - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: Task) : Task> = - FSharp.Control.Tasks.Affine.task { - do! t - return Ok() - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: ValueTask<_>) : Task> = - FSharp.Control.Tasks.Affine.task { - let! r = task - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask) : Task> = - FSharp.Control.Tasks.Affine.task { - do! t - return Ok() - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply<_>) : Task> = - FSharp.Control.Tasks.Affine.task { - let! p = p - return Ok p - } - - type BackgroundTaskResultBuilder with - - /// - /// Needed to allow `for..in` and `for..do` functionality - /// - member inline _.Source(s: #seq<_>) = s - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(result: Result<_, _>) : Task> = Task.singleton result - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(choice: Choice<_, _>) : Task> = - choice - |> Result.ofChoice - |> Task.singleton - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(asyncComputation: Async<_>) : Task> = - FSharp.Control.Tasks.NonAffine.task { - let! r = - asyncComputation - |> Async.StartImmediateAsTask - - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: Task<_>) : Task> = - FSharp.Control.Tasks.NonAffine.task { - let! r = task - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: Task) : Task> = - FSharp.Control.Tasks.NonAffine.task { - do! t - return Ok() - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(task: ValueTask<_>) : Task> = - FSharp.Control.Tasks.NonAffine.task { - let! r = task - return Ok r - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(t: ValueTask) : Task> = - FSharp.Control.Tasks.NonAffine.task { - do! t - return Ok() - } - - /// - /// Method lets us transform data types into our internal representation. - /// - member inline _.Source(p: Ply<_>) : Task> = - FSharp.Control.Tasks.NonAffine.task { - let! p = p - return Ok p - } - -#else - - open System open System.Runtime.CompilerServices open System.Threading @@ -693,18 +218,6 @@ type TaskResultBuilderBase() = member inline this.Source(taskResult: TaskResult<'T, 'Error>) : TaskResult<'T, 'Error> = taskResult - member inline _.Source(result: Async>) : Task> = - result - |> Async.StartImmediateAsTask - - member inline _.Source(t: ValueTask>) : Task> = task { return! t } - member inline _.Source(result: Result<_, _>) : Task> = Task.singleton result - - member inline _.Source(result: Choice<_, _>) : Task> = - result - |> Result.ofChoice - |> Task.singleton - type TaskResultBuilder() = @@ -1066,4 +579,22 @@ module TaskResultCEExtensionsMediumPriority = |> Async.map Ok |> Async.StartImmediateAsTask -#endif +[] +module TaskResultCEExtensionsHighPriority2 = + + // Medium priority extensions + type TaskResultBuilderBase with + + + member inline _.Source(result: Async>) : Task> = + result + |> Async.StartImmediateAsTask + + member inline _.Source(t: ValueTask>) : Task> = task { return! t } + + member inline _.Source(result: Result<_, _>) : Task> = Task.singleton result + + member inline _.Source(result: Choice<_, _>) : Task> = + result + |> Result.ofChoice + |> Task.singleton diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOp.fs b/src/FsToolkit.ErrorHandling/TaskResultOp.fs similarity index 100% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResultOp.fs rename to src/FsToolkit.ErrorHandling/TaskResultOp.fs diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOption.fs b/src/FsToolkit.ErrorHandling/TaskResultOption.fs similarity index 93% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResultOption.fs rename to src/FsToolkit.ErrorHandling/TaskResultOption.fs index 2334190d..411c3ec9 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOption.fs +++ b/src/FsToolkit.ErrorHandling/TaskResultOption.fs @@ -21,7 +21,7 @@ module TaskResultOption = let inline map3 ([] f) xTRO yTRO zTRO = TaskResult.map3 (Option.map3 f) xTRO yTRO zTRO - let inline retn value = TaskResult.retn (Ok value) + let inline retn value = TaskResult.retn (Some value) let inline apply fTRO xTRO = map2 (fun f x -> f x) fTRO xTRO diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOptionCE.fs b/src/FsToolkit.ErrorHandling/TaskResultOptionCE.fs similarity index 88% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResultOptionCE.fs rename to src/FsToolkit.ErrorHandling/TaskResultOptionCE.fs index d4dbae49..e80d0513 100644 --- a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/TaskResultOptionCE.fs @@ -2,54 +2,10 @@ namespace FsToolkit.ErrorHandling open System.Threading.Tasks open FsToolkit.ErrorHandling -#if NETSTANDARD2_0 -open FSharp.Control.Tasks.Affine.Unsafe -open FSharp.Control.Tasks.Affine -open Ply -#endif + [] module TaskResultOptionCE = -#if NETSTANDARD2_0 - type TaskResultOptionBuilder() = - member inline _.Return(value: 'T) : Ply> = - result.Return(Some value) - |> uply.Return - - member inline _.ReturnFrom - (taskResult: Task>) - : Ply> = - uply.ReturnFrom taskResult - - member inline _.Bind - ( - taskResult: Task>, - [] binder: 'T -> Ply> - ) : Ply> = - let binder' r = - match r with - | Ok(Some x) -> binder x - | Ok None -> - Ok None - |> uply.Return - | Error x -> - Error x - |> uply.Return - - uply.Bind(taskResult, binder') - - member inline _.Combine(tro1, tro2) = - tro1 - |> TaskResultOption.bind (fun _ -> tro2) - |> uply.ReturnFrom - - member inline _.Delay([] f) = uply.Delay f - - member inline _.Run([] f: unit -> Ply<'m>) = task.Run f - - let taskResultOption = TaskResultOptionBuilder() - -#else open System open System.Runtime.CompilerServices @@ -292,5 +248,3 @@ module TaskResultOptionCE = TaskResultOptionBuilder.RunDynamic(code) let taskResultOption = TaskResultOptionBuilder() - -#endif diff --git a/src/FsToolkit.ErrorHandling.TaskResult/TaskResultOptionOp.fs b/src/FsToolkit.ErrorHandling/TaskResultOptionOp.fs similarity index 100% rename from src/FsToolkit.ErrorHandling.TaskResult/TaskResultOptionOp.fs rename to src/FsToolkit.ErrorHandling/TaskResultOptionOp.fs diff --git a/src/FsToolkit.ErrorHandling/ValueOptionCE.fs b/src/FsToolkit.ErrorHandling/ValueOptionCE.fs index 7b7b038b..9b570098 100644 --- a/src/FsToolkit.ErrorHandling/ValueOptionCE.fs +++ b/src/FsToolkit.ErrorHandling/ValueOptionCE.fs @@ -103,8 +103,6 @@ module ValueOptionCE = |> ValueOption.ofObj |> ValueOption.map f - member inline _.MergeSources(option1, option2) = ValueOption.zip option1 option2 - /// /// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type. /// @@ -113,13 +111,6 @@ module ValueOptionCE = member inline _.Source(result: _ voption) : _ voption = result - // /// - // /// Method lets us transform data types into our internal representation. - // /// - member inline _.Source(vopt: _ option) : _ voption = - vopt - |> ValueOption.ofOption - let voption = ValueOptionBuilder() [] @@ -134,17 +125,6 @@ module ValueOptionExtensionsLower = m |> ValueOption.ofObj - member inline _.MergeSources(nullableObj1, option2) = - ValueOption.zip (ValueOption.ofObj nullableObj1) option2 - - - member inline _.MergeSources(option1, nullableObj2) = - ValueOption.zip (option1) (ValueOption.ofObj nullableObj2) - - - member inline _.MergeSources(nullableObj1, nullableObj2) = - ValueOption.zip (ValueOption.ofObj nullableObj1) (ValueOption.ofObj nullableObj2) - [] module ValueOptionExtensions = open System @@ -156,10 +136,18 @@ module ValueOptionExtensions = /// member inline _.Source(s: #seq<_>) = s - // /// - // /// Method lets us transform data types into our internal representation. - // /// + /// + /// Method lets us transform data types into our internal representation. + /// member inline _.Source(nullable: Nullable<'a>) : 'a voption = nullable |> ValueOption.ofNullable + + + /// + /// Method lets us transform data types into our internal representation. + /// + member inline _.Source(vopt: _ option) : _ voption = + vopt + |> ValueOption.ofOption #endif diff --git a/src/FsToolkit.ErrorHandling/paket.references b/src/FsToolkit.ErrorHandling/paket.references index 3fc2fc72..ee67a9cd 100644 --- a/src/FsToolkit.ErrorHandling/paket.references +++ b/src/FsToolkit.ErrorHandling/paket.references @@ -1,7 +1,3 @@ - +FSharp.Core Microsoft.SourceLink.GitHub - -group NetStandard2 - FSharp.Core -group NetStandard2_1 - FSharp.Core \ No newline at end of file +Microsoft.Bcl.AsyncInterfaces diff --git a/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/FsToolkit.ErrorHandling.AsyncSeq.Tests.fsproj b/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/FsToolkit.ErrorHandling.AsyncSeq.Tests.fsproj index b7247ff5..940f4ba8 100644 --- a/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/FsToolkit.ErrorHandling.AsyncSeq.Tests.fsproj +++ b/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/FsToolkit.ErrorHandling.AsyncSeq.Tests.fsproj @@ -1,27 +1,20 @@  - - Exe - net6.0;net7.0 - preview - - - - TargetFramework=netstandard2.0 - - - TargetFramework=netstandard2.0 - - - - - - - - - - - - - - \ No newline at end of file + + Exe + net8.0 + preview + + + + + + + + + + + + + diff --git a/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/paket.references b/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/paket.references index 61c21fb8..366db104 100644 --- a/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/paket.references +++ b/tests/FsToolkit.ErrorHandling.AsyncSeq.Tests/paket.references @@ -6,3 +6,4 @@ group Test YoloDev.Expecto.TestSdk Fable.Mocha Fable.Pyxpecto + Microsoft.Bcl.AsyncInterfaces diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs index 4c17871f..9c3f036d 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskResultCE.fs @@ -1115,9 +1115,23 @@ module CancellableTaskResultCE = ] ] + [] + let ``CancellableTaskResultCE inference checks`` = + testList "CancellableTaskResultCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = cancellableTaskResult { return! res } + + f (CancellableTaskResult.singleton ()) + |> ignore + ] + + [] let cancellableTaskResultTests = testList "CancellableTaskResult" [ cancellableTaskResultBuilderTests functionTests + ``CancellableTaskResultCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskValidationCE.fs b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskValidationCE.fs index 04cbd6ec..1d402a8c 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskValidationCE.fs +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/CancellableTaskValidationCE.fs @@ -19,11 +19,11 @@ module ValidationCompileTests = System.Console.WriteLine(dto) } - let testFunctionBCTV<'Dto> () = - backgroundCancellableTaskValidation { - let dto = Unchecked.defaultof<'Dto> - System.Console.WriteLine(dto) - } +// let testFunctionBCTV<'Dto> () = +// backgroundCancellableTaskValidation { +// let dto = Unchecked.defaultof<'Dto> +// System.Console.WriteLine(dto) +// } module CancellableTaskValidationCE = @@ -988,65 +988,336 @@ module CancellableTaskValidationCE = ] testList "applicatives" [ - testCaseTask "Happy Path Result" + testCaseTask "cancellableTaskValidation x cancellableTaskValidation" <| fun () -> task { let actual = cancellableTaskValidation { - let! a = Ok 3 - and! b = Ok 2 - and! c = Ok 1 - return a + b - c + let! a = cancellableTaskValidation { return 3 } + and! b = cancellableTaskValidation { return 3 } + return a + b } let! actual = actual CancellationToken.None - Expect.equal actual (Ok 4) "Should be ok" + Expect.equal actual (Ok 6) "Should be ok" } - testCaseTask "Happy Path Validation" + testCaseTask "cancellableTaskValidation x cancellableTask" <| fun () -> task { let actual = cancellableTaskValidation { - let! a = CancellableTaskValidation.ok 3 - and! b = CancellableTaskValidation.ok 2 - and! c = CancellableTaskValidation.ok 1 - return a + b - c + let! a = cancellableTaskValidation { return 3 } + and! b = cancellableTask { return 3 } + return a + b } let! actual = actual CancellationToken.None - Expect.equal actual (Ok 4) "Should be ok" + Expect.equal actual (Ok 6) "Should be ok" } - testCaseTask "Happy Path Result/Valiation" + testCaseTask "cancellableTaskValidation x taskResult" <| fun () -> task { let actual = cancellableTaskValidation { - let! a = CancellableTaskValidation.ok 3 - and! b = Ok 2 - and! c = CancellableTaskValidation.ok 1 - return a + b - c + let! a = cancellableTaskValidation { return 3 } + and! b = taskResult { return 3 } + return a + b } let! actual = actual CancellationToken.None - Expect.equal actual (Ok 4) "Should be ok" + Expect.equal actual (Ok 6) "Should be ok" } - testCaseTask "Happy Path Choice" + + testCaseTask "cancellableTaskValidation x taskValidation" <| fun () -> task { let actual = cancellableTaskValidation { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c + let! a = cancellableTaskValidation { return 3 } + and! b = task { return Validation.ok 3 } + return a + b } let! actual = actual CancellationToken.None - Expect.equal actual (Ok 4) "Should be ok" + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "cancellableTaskValidation x task" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! a = cancellableTaskValidation { return 3 } + and! b = task { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "cancellableTaskValidation x ok" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! a = cancellableTaskValidation { return 3 } + and! b = Ok 3 + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" } + testCaseTask "cancellableTask x cancellableTaskValidation " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = cancellableTaskValidation { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "cancellableTask x cancellableTask " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = cancellableTask { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "cancellableTask x taskResult " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = taskResult { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "cancellableTask x taskValidation " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = task { return Validation.Ok 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "cancellableTask x task " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = task { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "cancellableTask x ok " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = cancellableTask { return 3 } + and! a = Ok 3 + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "taskResult x cancellableTaskValidation " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = cancellableTaskValidation { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "taskResult x cancellableTask " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = cancellableTask { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "taskResult x taskResult " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = taskResult { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "taskResult x taskValidation " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = task { return Validation.ok 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + testCaseTask "taskResult x task " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = task { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + testCaseTask "taskResult x ok " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = taskResult { return 3 } + and! a = Ok 3 + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "task x cancellableTaskValidation " + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = task { return 3 } + and! a = cancellableTaskValidation { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "task x cancellableTask" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = task { return 3 } + and! a = cancellableTask { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "task x taskResult" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = task { return 3 } + and! a = taskResult { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "task x task" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = task { return 3 } + and! a = task { return 3 } + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + + testCaseTask "task x ok" + <| fun () -> + task { + let actual = + cancellableTaskValidation { + let! b = task { return 3 } + and! a = Ok 3 + return a + b + } + + let! actual = actual CancellationToken.None + Expect.equal actual (Ok 6) "Should be ok" + } + + testCaseTask "Happy Path Result/Choice/Validation" <| fun () -> task { @@ -1809,9 +2080,24 @@ module CancellableTaskValidationCE = ] ] + + let ``CancellableTaskValidationCE inference checks`` = + testList "CancellableTaskValidationCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = + cancellableTaskValidation { return! res } + + f (CancellableTaskValidation.ok (())) + |> ignore + ] + + [] let cancellableTaskValidationTests = testList "CancellableTaskValidation" [ cancellableTaskValidationBuilderTests functionTests + ``CancellableTaskValidationCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/Expect.fs b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/Expect.fs index 2688982b..b382a914 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/Expect.fs +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/Expect.fs @@ -18,10 +18,6 @@ module Expect = #endif -#if NETSTANDARD2_0 || NET6_0 - open FSharp.Control.Tasks -#endif - #if FABLE_COMPILER let isOk x message = diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/FsToolkit.ErrorHandling.IcedTasks.Tests.fsproj b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/FsToolkit.ErrorHandling.IcedTasks.Tests.fsproj index 48868ab1..e180c459 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/FsToolkit.ErrorHandling.IcedTasks.Tests.fsproj +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/FsToolkit.ErrorHandling.IcedTasks.Tests.fsproj @@ -1,22 +1,25 @@  - - Exe - net7.0 - - - - - - - - - - - - - - - - - \ No newline at end of file + + Exe + net8.0 + preview + $(NoWarn); FS3511 + + + + + + + + + + + + + + + + + diff --git a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/paket.references b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/paket.references index 1d933dbb..73fc962c 100644 --- a/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/paket.references +++ b/tests/FsToolkit.ErrorHandling.IcedTasks.Tests/paket.references @@ -1,5 +1,6 @@ group Test - Expecto - Microsoft.NET.Test.Sdk - YoloDev.Expecto.TestSdk - Fable.Pyxpecto + Expecto + Microsoft.NET.Test.Sdk + YoloDev.Expecto.TestSdk + Fable.Pyxpecto + Microsoft.Bcl.AsyncInterfaces diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj b/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj index 672b769e..8eb77427 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj @@ -1,41 +1,32 @@ - - Exe - net6.0;net7.0 - preview - - - - TargetFramework=netstandard2.0 - - - TargetFramework=netstandard2.0 - - - TargetFramework=netstandard2.0 - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + Exe + net8.0 + preview + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOptionCE.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOptionCE.fs index 639be7f9..dce8ba7f 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobOptionCE.fs @@ -332,3 +332,16 @@ let ceTests = Expect.equal actual (Some data) "Should be ok" } ] + + +[] +let ``JobOptionCE inference checks`` = + testList "JobOptionCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = jobOption { return! res } + + f (JobOption.retn ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultCE.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultCE.fs index 5049e020..50ca1e7c 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultCE.fs @@ -596,3 +596,16 @@ let ``AsyncResultCE applicative tests`` = Expect.equal actual (Error errorMsg) "Should be Error" } ] + + +[] +let ``JobResultCE inference checks`` = + testList "JobResultCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = jobResult { return! res } + + f (JobResult.retn ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultOption.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultOption.fs index 552faa24..8357f3bf 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultOption.fs +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResultOption.fs @@ -255,3 +255,15 @@ let operatorTests = } ) ] + +[] +let ``JobResultOptionCE inference checks`` = + testList "JobResultOptionCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = jobResultOption { return! res } + + f (JobResult.retn ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/paket.references b/tests/FsToolkit.ErrorHandling.JobResult.Tests/paket.references index ea4bd68b..209a9a29 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/paket.references +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/paket.references @@ -5,4 +5,4 @@ group Test YoloDev.Expecto.TestSdk Fable.Mocha Fable.Pyxpecto - Ply + Microsoft.Bcl.AsyncInterfaces diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskOptionCE.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskOptionCE.fs index 9335c0f3..dc5f2c4e 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskOptionCE.fs @@ -4,10 +4,6 @@ open Expecto open FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -let backgroundTask = FSharp.Control.Tasks.NonAffine.task -#endif - let makeDisposable () = { new System.IDisposable with member this.Dispose() = () @@ -483,3 +479,15 @@ let ceTestsApplicative = Expect.equal actual None "Should be ok" } ] + +[] +let ``BackgroundTaskOptionCE inference checks`` = + testList "BackgroundTaskOptionCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = backgroundTaskOption { return! res } + + f (TaskOption.some ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskResultCE.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskResultCE.fs index caa544e8..3931288d 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/BackgroundTaskResultCE.fs @@ -7,9 +7,6 @@ open TestData open FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -let backgroundTask = FSharp.Control.Tasks.NonAffine.task -#endif [] let ``BackgroundTaskResultCE return Tests`` = @@ -704,3 +701,16 @@ let ``BackgroundTaskResultCE applicative tests`` = Expect.equal actual (Error errorMsg) "Should be Error" } ] + + +[] +let ``BackgroundTaskResultCE inference checks`` = + testList "BackgroundTaskResultCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = backgroundTaskResult { return! res } + + f (TaskResult.ok ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj index 154963c0..a277e4c6 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj @@ -1,38 +1,31 @@ - - net7.0;net6.0; - preview - - - - TargetFramework=netstandard2.0 - - - TargetFramework=netstandard2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + net8.0 + preview + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/List.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/List.fs index 7331c08f..1f582dac 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/List.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/List.fs @@ -7,11 +7,6 @@ open TestHelpers open System open FsToolkit.ErrorHandling -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif - - let userId1 = Guid.NewGuid() let userId2 = Guid.NewGuid() let userId3 = Guid.NewGuid() diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/Result.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/Result.fs index 5840e80b..1a1bbc59 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/Result.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/Result.fs @@ -1,8 +1,5 @@ module Result -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif open Expecto open FsToolkit.ErrorHandling diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs index 36cae0e1..452b06cd 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOption.fs @@ -14,9 +14,6 @@ open Expecto open System open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif open TestData open TestHelpers open SampleDomain diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOptionCE.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOptionCE.fs index 0e951873..2d8cc33c 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskOptionCE.fs @@ -4,9 +4,6 @@ open Expecto open FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif module TestFuncs = let testFunctionTO<'Dto> () = @@ -15,10 +12,6 @@ module TestFuncs = System.Console.WriteLine(dto) } -let makeDisposable () = - { new System.IDisposable with - member this.Dispose() = () - } [] let ceTests = @@ -296,34 +289,101 @@ let ceTests = Expect.equal actual (Some data) "Should be ok" } - testCaseTask "Using disposeable" + + testCaseTask "use normal disposable" <| fun () -> task { let data = 42 + let mutable isFinished = false let! actual = taskOption { - use d = makeDisposable () + use d = TestHelpers.makeDisposable (fun () -> isFinished <- true) return data } Expect.equal actual (Some data) "Should be ok" + Expect.isTrue isFinished "" } - testCaseTask "Using bind disposeable" + testCaseTask "use! normal wrapped disposable" <| fun () -> task { let data = 42 + let mutable isFinished = false let! actual = taskOption { use! d = - (makeDisposable () - |> Some) + TestHelpers.makeDisposable (fun () -> isFinished <- true) + |> Some return data } Expect.equal actual (Some data) "Should be ok" + Expect.isTrue isFinished "" + } + testCaseTask "use null disposable" + <| fun () -> + task { + let data = 42 + + let! actual = + taskOption { + use d = null + return data + } + + Expect.equal actual (Some data) "Should be ok" + } + testCaseTask "use sync asyncdisposable" + <| fun () -> + task { + let data = 42 + let mutable isFinished = false + + let! actual = + taskOption { + use d = + TestHelpers.makeAsyncDisposable ( + (fun () -> + isFinished <- true + ValueTask() + ) + ) + + return data + } + + Expect.equal actual (Some data) "Should be ok" + Expect.isTrue isFinished "" + } + + testCaseTask "use async asyncdisposable" + <| fun () -> + task { + let data = 42 + let mutable isFinished = false + + let! actual = + taskOption { + use d = + TestHelpers.makeAsyncDisposable ( + (fun () -> + task { + do! Task.Yield() + isFinished <- true + } + :> Task + |> ValueTask + ) + ) + + return data + } + + Expect.equal actual (Some data) "Should be ok" + Expect.isTrue isFinished "" } yield! [ let maxIndices = [ @@ -551,3 +611,16 @@ let ceTestsApplicative = Expect.equal actual None "Should be ok" } ] + + +[] +let ``TaskOptionCE inference checks`` = + testList "TaskOptionCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = taskOption { return! res } + + f (TaskOption.some ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs index 8e30d5bb..a6f0c6ae 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs @@ -10,10 +10,6 @@ open FsToolkit.ErrorHandling.Operator.TaskResult open System open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif - let runTaskSync (task: Task<_>) = task.Result let createPostSuccess = diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultCE.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultCE.fs index 6696225e..ce590d29 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultCE.fs @@ -7,10 +7,6 @@ open TestData open FsToolkit.ErrorHandling open System.Threading.Tasks -#if NETSTANDARD2_0 || NET6_0 -open FSharp.Control.Tasks -#endif - [] let ``TaskResultCE return Tests`` = @@ -103,16 +99,6 @@ let ``TaskResultCE return! Tests`` = Expect.equal actual (Result.Ok()) "Should be ok" } -#if NETSTANDARD2_0 - testCaseTask "Return Ply" - <| fun () -> - task { - let innerData = "Foo" - let! actual = taskResult { return! Unsafe.uply { return innerData } } - - Expect.equal actual (Result.Ok innerData) "Should be ok" - } -#endif ] @@ -251,21 +237,6 @@ let ``TaskResultCE bind Tests`` = Expect.equal actual (Ok()) "Should be ok" } -#if NETSTANDARD2_0 - testCaseTask "Bind Ply" - <| fun () -> - task { - let innerData = "Foo" - - let! actual = - taskResult { - let! data = Unsafe.uply { return innerData } - return data - } - - Expect.equal actual (Result.Ok innerData) "Should be ok" - } -#endif ] @@ -352,10 +323,6 @@ let ``TaskResultCE try Tests`` = } ] -let makeDisposable () = - { new System.IDisposable with - member this.Dispose() = () - } [] let ``TaskResultCE using Tests`` = @@ -364,30 +331,34 @@ let ``TaskResultCE using Tests`` = <| fun () -> task { let data = 42 + let mutable isFinished = false let! actual = taskResult { - use d = makeDisposable () + use d = TestHelpers.makeDisposable (fun () -> isFinished <- true) return data } Expect.equal actual (Result.Ok data) "Should be ok" + Expect.isTrue isFinished "" } testCaseTask "use! normal wrapped disposable" <| fun () -> task { let data = 42 + let mutable isFinished = false let! actual = taskResult { use! d = - makeDisposable () + TestHelpers.makeDisposable (fun () -> isFinished <- true) |> Result.Ok return data } Expect.equal actual (Result.Ok data) "Should be ok" + Expect.isTrue isFinished "" } testCaseTask "use null disposable" <| fun () -> @@ -402,6 +373,55 @@ let ``TaskResultCE using Tests`` = Expect.equal actual (Result.Ok data) "Should be ok" } + testCaseTask "use sync asyncdisposable" + <| fun () -> + task { + let data = 42 + let mutable isFinished = false + + let! actual = + taskResult { + use d = + TestHelpers.makeAsyncDisposable ( + (fun () -> + isFinished <- true + ValueTask() + ) + ) + + return data + } + + Expect.equal actual (Result.Ok data) "Should be ok" + Expect.isTrue isFinished "" + } + + testCaseTask "use async asyncdisposable" + <| fun () -> + task { + let data = 42 + let mutable isFinished = false + + let! actual = + taskResult { + use d = + TestHelpers.makeAsyncDisposable ( + (fun () -> + task { + do! Task.Yield() + isFinished <- true + } + :> Task + |> ValueTask + ) + ) + + return data + } + + Expect.equal actual (Result.Ok data) "Should be ok" + Expect.isTrue isFinished "" + } ] @@ -639,12 +659,7 @@ let ``TaskResultCE applicative tests`` = Expect.equal actual (Ok 5) "Should be ok" } - let specialCaseTask returnValue = -#if NETSTANDARD2_0 - Unsafe.uply { return returnValue } -#else - Task.FromResult returnValue -#endif + let specialCaseTask returnValue = Task.FromResult returnValue testCaseTask "Happy Path Result/Choice/AsyncResult/Ply/ValueTask" <| fun () -> @@ -723,3 +738,16 @@ let ``TaskResultCE applicative tests`` = Expect.equal actual (Error errorMsg) "Should be Error" } ] + + +[] +let ``TaskResultCE inference checks`` = + testList "TaskResultCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = taskResult { return! res () } + + f (TaskResult.retn) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultOption.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultOption.fs index 7415e510..860b40fa 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultOption.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResultOption.fs @@ -255,3 +255,16 @@ let operatorTests = } ) ] + + +[] +let ``TaskResultOptionCE inference checks`` = + testList "TaskResultOption inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = taskResultOption { return! res } + + f (TaskResultOption.retn ()) + |> ignore + ] diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/paket.references b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/paket.references index 0d12decb..65004021 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/paket.references +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/paket.references @@ -6,4 +6,4 @@ group Test YoloDev.Expecto.TestSdk Fable.Mocha Fable.Pyxpecto - Ply + Microsoft.Bcl.AsyncInterfaces diff --git a/tests/FsToolkit.ErrorHandling.Tests/AsyncOptionCE.fs b/tests/FsToolkit.ErrorHandling.Tests/AsyncOptionCE.fs index 5ce2bb0c..13a40b44 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/AsyncOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/AsyncOptionCE.fs @@ -233,17 +233,6 @@ let ``AsyncOptionCE try Tests`` = } ] -let makeDisposable (callback) = - { new System.IDisposable with - member this.Dispose() = callback () - } - - -let makeAsyncDisposable (callback) = - { new System.IAsyncDisposable with - member this.DisposeAsync() = callback () - } - let ``AsyncOptionCE using Tests`` = testList "AsyncOptionCE using Tests" [ @@ -254,7 +243,7 @@ let ``AsyncOptionCE using Tests`` = let! actual = asyncOption { - use d = makeDisposable ((fun () -> isFinished <- true)) + use d = TestHelpers.makeDisposable ((fun () -> isFinished <- true)) return data } @@ -271,7 +260,7 @@ let ``AsyncOptionCE using Tests`` = let! actual = asyncOption { use d = - makeDisposable (fun () -> + TestHelpers.makeDisposable (fun () -> disposed <- true if not finished then @@ -296,7 +285,7 @@ let ``AsyncOptionCE using Tests`` = let! actual = asyncOption { use d = - makeAsyncDisposable ( + TestHelpers.makeAsyncDisposable ( (fun () -> isFinished <- true ValueTask() @@ -317,7 +306,7 @@ let ``AsyncOptionCE using Tests`` = let! actual = asyncOption { use d = - makeAsyncDisposable ( + TestHelpers.makeAsyncDisposable ( (fun () -> task { do! Task.Yield() @@ -342,7 +331,7 @@ let ``AsyncOptionCE using Tests`` = let! actual = asyncOption { use! d = - makeDisposable (id) + TestHelpers.makeDisposable (id) |> Some return data @@ -568,9 +557,20 @@ let ``AsyncOptionCE Stack Trace Tests`` = #else testList "AsyncOptionCE Stack Trace Tests" [] - #endif + +let ``AsyncOptionCE inference checks`` = + testList "AsyncOptionCE inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = asyncOption { return! res } + + f (AsyncOption.some ()) + |> ignore + ] + let allTests = testList "AsyncResultCETests" [ ``AsyncOptionCE return Tests`` @@ -581,4 +581,5 @@ let allTests = ``AsyncOptionCE using Tests`` ``AsyncOptionCE loop Tests`` ``AsyncOptionCE Stack Trace Tests`` + ``AsyncOptionCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/AsyncResultCE.fs b/tests/FsToolkit.ErrorHandling.Tests/AsyncResultCE.fs index 8966c2e8..da5949dd 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/AsyncResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/AsyncResultCE.fs @@ -253,18 +253,6 @@ let ``AsyncResultCE try Tests`` = } ] -let makeDisposable (callback) = - { new System.IDisposable with - member this.Dispose() = callback () - } - - -let makeAsyncDisposable (callback) = - { new System.IAsyncDisposable with - member this.DisposeAsync() = callback () - } - - let ``AsyncResultCE using Tests`` = testList "AsyncResultCE using Tests" [ testCaseAsync "use normal disposable" @@ -274,14 +262,14 @@ let ``AsyncResultCE using Tests`` = let! actual = asyncResult { - use d = makeDisposable ((fun () -> isFinished <- true)) + use d = TestHelpers.makeDisposable ((fun () -> isFinished <- true)) return data } Expect.equal actual (Result.Ok data) "Should be ok" Expect.isTrue isFinished "Expected disposable to be disposed" } -#if NET7_0 +#if !FABLE_COMPILER testCaseAsync "use sync asyncdisposable" <| async { let data = 42 @@ -290,7 +278,7 @@ let ``AsyncResultCE using Tests`` = let! actual = asyncResult { use d = - makeAsyncDisposable ( + TestHelpers.makeAsyncDisposable ( (fun () -> isFinished <- true ValueTask() @@ -311,7 +299,7 @@ let ``AsyncResultCE using Tests`` = let! actual = asyncResult { use d = - makeAsyncDisposable ( + TestHelpers.makeAsyncDisposable ( (fun () -> task { do! Task.Yield() @@ -329,6 +317,7 @@ let ``AsyncResultCE using Tests`` = Expect.isTrue isFinished "Expected disposable to be disposed" } #endif + testCaseAsync "use! normal wrapped disposable" <| async { let data = 42 @@ -336,7 +325,7 @@ let ``AsyncResultCE using Tests`` = let! actual = asyncResult { use! d = - makeDisposable (id) + TestHelpers.makeDisposable (id) |> Result.Ok return data @@ -354,7 +343,7 @@ let ``AsyncResultCE using Tests`` = let! actual = asyncResult { use d = - makeDisposable (fun () -> + TestHelpers.makeDisposable (fun () -> disposed <- true if not finished then @@ -537,173 +526,6 @@ let toTaskResult v = |> Task.FromResult #endif -let ``AsyncResultCE applicative tests`` = - testList "AsyncResultCE applicative tests" [ - testCaseAsync "Happy Path AsyncResult" - <| async { - let! actual = - asyncResult { - let! a = AsyncResult.retn 3 - and! b = AsyncResult.retn 2 - and! c = AsyncResult.retn 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - -#if !FABLE_COMPILER - - testCaseAsync "Happy Path TaskResult" - <| async { - let! actual = - asyncResult { - let! a = toTaskResult 3 - and! b = toTaskResult 2 - and! c = toTaskResult 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - -#endif - - testCaseAsync "Happy Path Result" - <| async { - let! actual = - asyncResult { - let! a = Result.Ok 3 - and! b = Result.Ok 2 - and! c = Result.Ok 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - - testCaseAsync "Happy Path Choice" - <| async { - let! actual = - asyncResult { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - - // Cannot get this to compile properly - testCaseAsync "Happy Path Async" - <| async { - let! actual = - asyncResult { - let! a = Async.singleton 3 //: Async - and! b = Async.singleton 2 //: Async - and! c = Async.singleton 1 //: Async - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - - testCaseAsync "Happy Path 2 Async" - <| async { - let! actual = - asyncResult { - let! a = Async.singleton 3 //: Async - and! b = Async.singleton 2 //: Async - return a + b - } - - Expect.equal actual (Ok 5) "Should be ok" - } - -#if !FABLE_COMPILER - - testCaseAsync "Happy Path 2 Task" - <| async { - let! actual = - asyncResult { - let! a = Task.FromResult 3 - and! b = Task.FromResult 2 - return a + b - } - - Expect.equal actual (Ok 5) "Should be ok" - } - -#endif - - testCaseAsync "Happy Path Result/Choice/AsyncResult" - <| async { - let! actual = - asyncResult { - let! a = Ok 3 - and! b = Choice1Of2 2 - - and! c = - Ok 1 - |> Async.singleton - - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - } - - testCaseAsync "Fail Path Result" - <| async { - let expected = Error "TryParse failure" - - let! actual = - asyncResult { - let! a = Ok 3 - and! b = Ok 2 - and! c = expected - return a + b - c - } - - Expect.equal actual expected "Should be Error" - } - - testCaseAsync "Fail Path Choice" - <| async { - let errorMsg = "TryParse failure" - - let! actual = - asyncResult { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice2Of2 errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - } - - testCaseAsync "Fail Path Result/Choice/AsyncResult" - <| async { - let errorMsg = "TryParse failure" - - let! actual = - asyncResult { - let! a = Choice1Of2 3 - - and! b = - Ok 2 - |> Async.singleton - - and! c = Error errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - } - ] - let ``AsyncResultCE Stack Trace Tests`` = @@ -758,6 +580,19 @@ let ``AsyncResultCE Stack Trace Tests`` = #endif + +let ``AsyncResultCE inference checks`` = + testList "AsyncResultCEInference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = asyncResult { return! res } + + f (AsyncResult.retn ()) + |> ignore + ] + + let allTests = testList "AsyncResultCETests" [ ``AsyncResultCE return Tests`` @@ -767,6 +602,6 @@ let allTests = ``AsyncResultCE try Tests`` ``AsyncResultCE using Tests`` ``AsyncResultCE loop Tests`` - ``AsyncResultCE applicative tests`` ``AsyncResultCE Stack Trace Tests`` + ``AsyncResultCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/AsyncResultOptionCE.fs b/tests/FsToolkit.ErrorHandling.Tests/AsyncResultOptionCE.fs index cf18d83d..5997ee3c 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/AsyncResultOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/AsyncResultOptionCE.fs @@ -438,16 +438,6 @@ let ``AsyncResultOptionCE try Tests`` = } ] -let makeDisposable callback = - { new System.IDisposable with - member this.Dispose() = callback () - } - -let makeAsyncDisposable (callback) = - { new System.IAsyncDisposable with - member this.DisposeAsync() = callback () - } - let ``AsyncResultOptionCE using Tests`` = testList "AsyncResultOptionCE using Tests" [ @@ -456,9 +446,10 @@ let ``AsyncResultOptionCE using Tests`` = let data = 42 let mutable isFinished = false + let! actual = asyncResultOption { - use d = makeDisposable (fun () -> isFinished <- true) + use d = TestHelpers.makeDisposable (fun () -> isFinished <- true) return data } @@ -490,8 +481,7 @@ let ``AsyncResultOptionCE using Tests`` = Expect.equal actual (Ok(Some 42)) "Should be ok" Expect.isTrue disposed "Should be disposed" } - -#if NET7_0 +#if !FABLE_COMPILER testCaseAsync "use sync asyncdisposable" <| async { let data = 42 @@ -521,7 +511,7 @@ let ``AsyncResultOptionCE using Tests`` = let! actual = asyncResultOption { use d = - makeAsyncDisposable ( + TestHelpers.makeAsyncDisposable ( (fun () -> task { do! Task.Yield() @@ -548,7 +538,7 @@ let ``AsyncResultOptionCE using Tests`` = let! actual = asyncResultOption { use! d = - makeDisposable (fun () -> isFinished <- true) + TestHelpers.makeDisposable (fun () -> isFinished <- true) |> Result.Ok return data @@ -716,6 +706,19 @@ let ``AsyncResultOptionCE loop Tests`` = } ] + +let ``AsyncResultOptionCE inference checks`` = + testList "AsyncResultOptionCE Inference checks" [ + testCase "Inference checks" + <| fun () -> + // Compilation is success + let f res = asyncResultOption { return! res } + + f (AsyncResultOption.retn ()) + |> ignore + ] + + let allTests = testList "AsyncResultCETests" [ ``AsyncResultOptionCE return Tests`` @@ -725,4 +728,5 @@ let allTests = ``AsyncResultOptionCE try Tests`` ``AsyncResultOptionCE using Tests`` ``AsyncResultOptionCE loop Tests`` + ``AsyncResultOptionCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/Expect.fs b/tests/FsToolkit.ErrorHandling.Tests/Expect.fs index 591259e0..babfe4d8 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/Expect.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/Expect.fs @@ -18,11 +18,6 @@ module Expect = #endif -#if NETSTANDARD2_0 || NET6_0 - open FSharp.Control.Tasks -#endif - - #if FABLE_COMPILER let isOk x message = match x with diff --git a/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj b/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj index b52c5140..386d89b9 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj +++ b/tests/FsToolkit.ErrorHandling.Tests/FsToolkit.ErrorHandling.Tests.fsproj @@ -1,20 +1,16 @@ - + Exe - net6.0;net7.0 + net8.0 preview - - - TargetFramework=netstandard2.0 - - - + + diff --git a/tests/FsToolkit.ErrorHandling.Tests/OptionCE.fs b/tests/FsToolkit.ErrorHandling.Tests/OptionCE.fs index 5fff452e..4dac455a 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/OptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/OptionCE.fs @@ -319,228 +319,19 @@ type CustomClass(x: int) = member _.getX = x -let ``OptionCE applicative tests`` = - testList "OptionCE applicative tests" [ - testCase "Happy Path Option.Some" +let ``OptionCE inference checks`` = + testList "OptionCE Inference checks" [ + testCase "Inference checks" <| fun () -> - let actual = - option { - let! a = Some 3 - and! b = Some 2 - and! c = Some 1 - return a + b - c - } - - Expect.equal actual (Some 4) "Should be Some 4" - - testCase "Happy Path Nullable" - <| fun () -> - let actual = - option { - let! a = Nullable<_> 3 - and! b = Nullable<_> 2 - and! c = Nullable<_> 1 - return a + b - c - } - - Expect.equal actual (Some 4) "Should be Some 4" - - testCase "Happy Path null Objects" - <| fun () -> - // let hello = CustomClass - let actual = - option { - let! a = CustomClass 3 - and! b = CustomClass 2 - and! c = CustomClass 1 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (Some 4) "Should be Some 4" - - - testCase "Happy Path strings" - <| fun () -> - let hello = "Hello " - let world = "world " - let fromfsharp = "from F#" - - let actual = - option { - let! a = hello - and! b = world - and! c = fromfsharp - return a + b + c - } - - Expect.equal actual (Some "Hello world from F#") "Should be Some" - - testCase "Happy Path ResizeArray" - <| fun () -> - let r1 = ResizeArray [ 3 ] - let r2 = ResizeArray [ 2 ] - let r3 = ResizeArray [ 1 ] - - let actual = - option { - let! a = r1 - and! b = r2 - and! c = r3 - a.AddRange b - a.AddRange c - - return Seq.sum a - } - - Expect.equal actual (Some 6) "Should be Some" - - testCase "Happy Path Option.Some/Nullable" - <| fun () -> - let actual = - option { - let! a = Some 3 - and! b = Nullable 2 - and! c = Nullable 1 - return a + b - c - } - - Expect.equal actual (Some 4) "Should be Some 4" - - testCase "Happy Path Option.Some/Nullable/Objects" - <| fun () -> - let actual = - option { - let! a = Some 3 - and! b = Nullable 2 - and! c = CustomClass 1 - - return - a + b - - c.getX - } - - Expect.equal actual (Some 4) "Should be Some 4" - - - testCase "Happy Combo all" - <| fun () -> - let actual = - option { - let! a = Nullable<_> 3 - and! b = Some 2 - and! c = "hello" - and! d = ResizeArray [ 1 ] - and! e = CustomClass 5 - and! f = Uri "https://github.com/" - return sprintf "%d %d %s %d %d %s" a b c (Seq.head d) e.getX (string f) - } - - Expect.equal actual (Some "3 2 hello 1 5 https://github.com/") "Should be Some" - testCase "Fail Path Option.None" - <| fun () -> - let actual = - option { - let! a = Some 3 - and! b = Some 2 - and! c = None - return a + b - c - } - - Expect.equal actual None "Should be None" - - testCase "Fail Path Nullable" - <| fun () -> - let actual = - option { - let! a = Nullable 3 - and! b = Nullable 2 - and! c = Nullable<_>() - return a + b - c - } - - Expect.equal actual (None) "Should be None" - - testCase "Fail Path Objects" - <| fun () -> - let c1 = CustomClass 3 - let c2 = CustomClass 2 - let c3: CustomClass = null - - let actual = - option { - let! a = c1 - and! b = c2 - and! c = c3 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (None) "Should be None" - - - testCase "Fail Path strings" - <| fun () -> - let c1 = CustomClass 3 - let c2 = CustomClass 2 - let c3: CustomClass = null - - let actual = - option { - let! a = c1 - and! b = c2 - and! c = c3 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (None) "Should be None" - - testCase "Fail Path Option.Some/Nullable" - <| fun () -> - let actual = - option { - let! a = Nullable<_> 3 - and! b = Some 2 - and! c = Nullable<_>() - return a + b - c - } - - Expect.equal actual None "Should be None" + // Compilation is success + let f res = option { return! res } - testCase "ValueOption.Some" - <| fun () -> - let actual = - option { - let! a = ValueSome 3 - return a - } - - Expect.equal actual (Some 3) "Should be None" - - testCase "ValueOption.None" - <| fun () -> - let actual = - option { - let! a = ValueNone - return a - } - - Expect.equal actual (None) "Should be None" + f (Some()) + |> ignore ] - let allTests = testList "Option CE tests" [ ceTests - ``OptionCE applicative tests`` + ``OptionCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/ResultCE.fs b/tests/FsToolkit.ErrorHandling.Tests/ResultCE.fs index e34d0465..7b7d4c98 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/ResultCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/ResultCE.fs @@ -338,103 +338,18 @@ let ``ResultCE loop Tests`` = Expect.equal actual (Result.Ok data) "Should be ok" ] -let ``ResultCE applicative tests`` = - testList "ResultCE applicative tests" [ - testCase "Happy Path Result" - <| fun () -> - let actual = - result { - let! a = Ok 3 - and! b = Ok 2 - and! c = Ok 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - - testCase "Happy Path Choice" - <| fun () -> - let actual = - result { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - - testCase "Happy Path Result/Choice" - <| fun () -> - let actual = - result { - let! a = Ok 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c - } - - Expect.equal actual (Ok 4) "Should be ok" - - testCase "Fail Path Result" - <| fun () -> - let expected = Error "TryParse failure" - - let actual = - result { - let! a = Ok 3 - and! b = Ok 2 - and! c = expected - return a + b - c - } - Expect.equal actual expected "Should be Error" - - testCase "Fail Path Choice" - <| fun () -> - let errorMsg = "TryParse failure" - - let actual = - result { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice2Of2 errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - - testCase "Fail Path Result/Choice" +let ``ResultCE inference checks`` = + testList "ResultCE Inference checks" [ + testCase "Inference checks" <| fun () -> - let errorMsg = "TryParse failure" - - let actual = - result { - let! a = Choice1Of2 3 - and! b = Ok 2 - and! c = Error errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - - testCase "Multiple errors" - <| fun () -> - let errorMsg1 = "TryParse failure" - let errorMsg2 = "IO failure" - - let actual = - result { - let! a = Choice1Of2 3 - and! b = Error errorMsg1 - and! c = Error errorMsg2 - return a + b - c - } + // Compilation is success + let f res = result { return! res } - Expect.equal actual (Error errorMsg1) "Should be Error" + f (Ok()) + |> ignore ] - let allTests = testList "Result CE Tests" [ ``ResultCE return Tests`` @@ -444,5 +359,5 @@ let allTests = ``ResultCE try Tests`` ``ResultCE using Tests`` ``ResultCE loop Tests`` - ``ResultCE applicative tests`` + ``ResultCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/ResultOptionCE.fs b/tests/FsToolkit.ErrorHandling.Tests/ResultOptionCE.fs index 661bfc8b..81b3096e 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/ResultOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/ResultOptionCE.fs @@ -415,102 +415,19 @@ let ``ResultOptionCE loop Tests`` = Expect.equal actual (Ok(Some data)) "Should be ok some" ] -let ``ResultOptionCE applicative tests`` = - testList "ResultOptionCE applicative tests" [ - testCase "Happy Path Result" - <| fun () -> - let actual = - resultOption { - let! a = Ok(Some 3) - and! b = Ok(Some 2) - and! c = Ok(Some 1) - return a + b - c - } - - Expect.equal actual (Ok(Some 4)) "Should be ok some" - - testCase "Happy Path Choice" - <| fun () -> - let actual = - resultOption { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c - } - - Expect.equal actual (Ok(Some 4)) "Should be ok some" - testCase "Happy Path Result/Choice" +let ``ResultOptionCE inference checks`` = + testList "ResultOptionCE Inference checks" [ + testCase "Inference checks" <| fun () -> - let actual = - resultOption { - let! a = Ok 3 - and! b = Choice1Of2 2 - and! c = Choice1Of2 1 - return a + b - c - } - - Expect.equal actual (Ok(Some 4)) "Should be ok some" - - testCase "Fail Path Result" - <| fun () -> - let expected = Error "TryParse failure" - - let actual = - resultOption { - let! a = Ok 3 - and! b = Ok 2 - and! c = expected - return a + b - c - } - - Expect.equal actual expected "Should be Error" + // Compilation is success + let f res = resultOption { return! res } - testCase "Fail Path Choice" - <| fun () -> - let errorMsg = "TryParse failure" - - let actual = - resultOption { - let! a = Choice1Of2 3 - and! b = Choice1Of2 2 - and! c = Choice2Of2 errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - - testCase "Fail Path Result/Choice" - <| fun () -> - let errorMsg = "TryParse failure" - - let actual = - resultOption { - let! a = Choice1Of2 3 - and! b = Ok 2 - and! c = Error errorMsg - return a + b - c - } - - Expect.equal actual (Error errorMsg) "Should be Error" - - testCase "Multiple errors" - <| fun () -> - let errorMsg1 = "TryParse failure" - let errorMsg2 = "IO failure" - - let actual = - resultOption { - let! a = Choice1Of2 3 - and! b = Error errorMsg1 - and! c = Error errorMsg2 - return a + b - c - } - - Expect.equal actual (Error errorMsg1) "Should be Error" + f (Ok(Some())) + |> ignore ] + let allTests = testList "Result CE Tests" [ ``ResultOptionCE return Tests`` @@ -519,5 +436,5 @@ let allTests = ``ResultOptionCE try Tests`` ``ResultOptionCE using Tests`` ``ResultOptionCE loop Tests`` - ``ResultOptionCE applicative tests`` + ``ResultOptionCE inference checks`` ] diff --git a/tests/FsToolkit.ErrorHandling.Tests/TestHelpers.fs b/tests/FsToolkit.ErrorHandling.Tests/TestHelpers.fs new file mode 100644 index 00000000..9aa9f25f --- /dev/null +++ b/tests/FsToolkit.ErrorHandling.Tests/TestHelpers.fs @@ -0,0 +1,13 @@ +namespace FsToolkit.ErrorHandling + + +module TestHelpers = + let makeDisposable (callback) = + { new System.IDisposable with + member this.Dispose() = callback () + } + + let makeAsyncDisposable (callback) = + { new System.IAsyncDisposable with + member this.DisposeAsync() = callback () + } diff --git a/tests/FsToolkit.ErrorHandling.Tests/ValueOptionCE.fs b/tests/FsToolkit.ErrorHandling.Tests/ValueOptionCE.fs index 0a563257..40ad5056 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/ValueOptionCE.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/ValueOptionCE.fs @@ -325,230 +325,22 @@ type CustomClass(x: int) = member _.getX = x -let ``ValueOptionCE applicative tests`` = - testList "ValueOptionCE applicative tests" [ - testCase "Happy Path ValueOption.ValueSome" +let ``ValueOptionCE inference checks`` = + testList "ValueOptionCE Inference checks" [ + testCase "Inference checks" <| fun () -> - let actual = - voption { - let! a = ValueSome 3 - and! b = ValueSome 2 - and! c = ValueSome 1 - return a + b - c - } - - Expect.equal actual (ValueSome 4) "Should be ValueSome 4" - - testCase "Happy Path Nullable" - <| fun () -> - let actual = - voption { - let! a = Nullable<_> 3 - and! b = Nullable<_> 2 - and! c = Nullable<_> 1 - return a + b - c - } - - Expect.equal actual (ValueSome 4) "Should be ValueSome 4" - - testCase "Happy Path null Objects" - <| fun () -> - // let hello = CustomClass - let actual = - voption { - let! a = CustomClass 3 - and! b = CustomClass 2 - and! c = CustomClass 1 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (ValueSome 4) "Should be ValueSome 4" - - - testCase "Happy Path strings" - <| fun () -> - let hello = "Hello " - let world = "world " - let fromfsharp = "from F#" - - let actual = - voption { - let! a = hello - and! b = world - and! c = fromfsharp - return a + b + c - } - - Expect.equal actual (ValueSome "Hello world from F#") "Should be Some" - - testCase "Happy Path ResizeArray" - <| fun () -> - let r1 = ResizeArray [ 3 ] - let r2 = ResizeArray [ 2 ] - let r3 = ResizeArray [ 1 ] - - let actual = - voption { - let! a = r1 - and! b = r2 - and! c = r3 - a.AddRange b - a.AddRange c - - return Seq.sum a - } - - Expect.equal actual (ValueSome 6) "Should be Some" - - testCase "Happy Path Option.Some/Nullable" - <| fun () -> - let actual = - voption { - let! a = ValueSome 3 - and! b = Nullable 2 - and! c = Nullable 1 - return a + b - c - } - - Expect.equal actual (ValueSome 4) "Should be ValueSome 4" - - testCase "Happy Path Option.Some/Nullable/Objects" - <| fun () -> - let actual = - voption { - let! a = ValueSome 3 - and! b = Nullable 2 - and! c = CustomClass 1 - - return - a + b - - c.getX - } - - Expect.equal actual (ValueSome 4) "Should be ValueSome 4" - - - testCase "Happy Combo all" - <| fun () -> - let actual = - voption { - let! a = Nullable<_> 3 - and! b = ValueSome 2 - and! c = "hello" - and! d = ResizeArray [ 1 ] - and! e = CustomClass 5 - and! f = Uri "https://github.com/" - return sprintf "%d %d %s %d %d %s" a b c (Seq.head d) e.getX (string f) - } - - Expect.equal actual (ValueSome "3 2 hello 1 5 https://github.com/") "Should be Some" - testCase "Fail Path ValueOption.ValueNone" - <| fun () -> - let actual = - voption { - let! a = ValueSome 3 - and! b = ValueSome 2 - and! c = None - return a + b - c - } - - Expect.equal actual ValueNone "Should be None" - - testCase "Fail Path Nullable" - <| fun () -> - let actual = - voption { - let! a = Nullable 3 - and! b = Nullable 2 - and! c = Nullable<_>() - return a + b - c - } - - Expect.equal actual (ValueNone) "Should be None" - - testCase "Fail Path Objects" - <| fun () -> - let c1 = CustomClass 3 - let c2 = CustomClass 2 - let c3: CustomClass = null - - let actual = - voption { - let! a = c1 - and! b = c2 - and! c = c3 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (ValueNone) "Should be None" - - - testCase "Fail Path strings" - <| fun () -> - let c1 = CustomClass 3 - let c2 = CustomClass 2 - let c3: CustomClass = null - - let actual = - voption { - let! a = c1 - and! b = c2 - and! c = c3 - - return - a.getX - + b.getX - - c.getX - } - - Expect.equal actual (ValueNone) "Should be None" - - testCase "Fail Path ValueOption.ValueSome/Nullable" - <| fun () -> - let actual = - voption { - let! a = Nullable<_> 3 - and! b = ValueSome 2 - and! c = Nullable<_>() - return a + b - c - } - - Expect.equal actual ValueNone "Should be None" - - testCase "ValueOption.ValueSome" - <| fun () -> - let actual = - voption { - let! a = ValueSome 3 - return a - } - - Expect.equal actual (ValueSome 3) "Should be None" - - testCase "ValueOption.ValueNone" - <| fun () -> - let actual = - voption { - let! a = ValueNone - return a - } + // Compilation is success + let f res = voption { return! res } - Expect.equal actual (ValueNone) "Should be None" + f (ValueSome()) + |> ignore ] let allTests = testList "ValueOption CE tests" [ ceTests - ``ValueOptionCE applicative tests`` + ``ValueOptionCE inference checks`` ] #else let allTests = testList "ValueOption CE tests" [] diff --git a/tests/FsToolkit.ErrorHandling.Tests/paket.references b/tests/FsToolkit.ErrorHandling.Tests/paket.references index ad4a6c5b..366db104 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/paket.references +++ b/tests/FsToolkit.ErrorHandling.Tests/paket.references @@ -1,9 +1,9 @@ group Test FSharp.Core - Ply Expecto Expecto.Hopac Microsoft.NET.Test.Sdk YoloDev.Expecto.TestSdk Fable.Mocha Fable.Pyxpecto + Microsoft.Bcl.AsyncInterfaces diff --git a/tools/FunctionMap/FunctionMap.fsproj b/tools/FunctionMap/FunctionMap.fsproj index b5e6bd66..7ddc8cf2 100644 --- a/tools/FunctionMap/FunctionMap.fsproj +++ b/tools/FunctionMap/FunctionMap.fsproj @@ -1,19 +1,21 @@  - - Exe - net6.0 - false - false - - - - - - - - - - - - \ No newline at end of file + + Exe + net6.0 + false + false + + + + + + + + + + + + diff --git a/tools/FunctionMap/paket.references b/tools/FunctionMap/paket.references index 1b2c8d6a..6f627f42 100644 --- a/tools/FunctionMap/paket.references +++ b/tools/FunctionMap/paket.references @@ -1,2 +1 @@ -group NetStandard2_1 - FSharp.Core \ No newline at end of file +FSharp.Core