Skip to content

Commit

Permalink
Use Microsoft.Bcl.AsyncInterfaces in netstandard2.0 (#39)
Browse files Browse the repository at this point in the history
* Use Microsoft.Bcl.AsyncInterfaces in netstandard2.0

* Make own IAsyncEnumerable

* Fix AsyncEx IAsyncEnum impl

* Fix stalling
  • Loading branch information
TheAngryByrd authored Jan 31, 2024
1 parent 3762de1 commit 2090b7c
Show file tree
Hide file tree
Showing 28 changed files with 155 additions and 209 deletions.
3 changes: 1 addition & 2 deletions build/build.fs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ module DocsTool =
let build (configuration) =
Fsdocs.build fsDocsDotnetOptions (fsDocsBuildParams configuration)


let watch (configuration) =
let buildParams bp =
let bp =
Expand Down Expand Up @@ -276,7 +275,7 @@ let maxCpuMsBuild =
lazy
(match maxCpuCount.Value with
| None -> ""
| Some None -> "/m:"
| Some None -> "/m"
| Some(Some x) -> $"/m:%d{x}")

let allPublishChecks () =
Expand Down
2 changes: 2 additions & 0 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ nuget FSharp.Core >= 6.0.1
nuget Microsoft.SourceLink.GitHub 1.1.1 copy_local: true
nuget BenchmarkDotNet >= 0.13.9
nuget Ply >= 0.3.1
nuget Microsoft.Bcl.AsyncInterfaces >= 6.0.0 framework:netstandard2.0


group Test
Expand All @@ -15,6 +16,7 @@ group Test
source https://api.nuget.org/v3/index.json
nuget Expecto >= 10.1.0
nuget Microsoft.Bcl.TimeProvider
nuget Microsoft.Bcl.AsyncInterfaces >= 8
nuget TimeProviderExtensions
nuget YoloDev.Expecto.TestSdk >= 0.14.2
nuget Microsoft.NET.Test.Sdk >= 17.7.2
Expand Down
8 changes: 4 additions & 4 deletions paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ NUGET
FSharp.Core (6.0.1)
Gee.External.Capstone (2.3) - restriction: >= netstandard2.0
Iced (1.17) - restriction: >= netstandard2.0
Microsoft.Bcl.AsyncInterfaces (1.1) - restriction: >= netstandard2.0
System.Threading.Tasks.Extensions (>= 4.5.2) - restriction: || (>= net461) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) (&& (< netcoreapp2.1) (>= 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 (1.1.1) - copy_local: true
Microsoft.CodeAnalysis.Analyzers (3.3.3) - restriction: >= netstandard2.0
Microsoft.CodeAnalysis.Common (4.1) - restriction: >= netstandard2.0
Expand Down Expand Up @@ -112,7 +112,7 @@ NUGET
System.Text.Encoding.CodePages (4.5.1) - restriction: >= netstandard2.0
Microsoft.NETCore.Platforms (>= 2.1.2) - restriction: && (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)
System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - restriction: || (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos))
System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (< netcoreapp2.1) (>= netstandard2.1)) (>= 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 Build
Expand Down Expand Up @@ -367,7 +367,7 @@ NUGET
FSharp.Control.TaskSeq (0.3)
FSharp.Core (>= 6.0.2) - restriction: >= netstandard2.1
FSharp.Core (7.0.401) - restriction: >= netstandard2.1
Microsoft.Bcl.AsyncInterfaces (7.0) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0))
Microsoft.Bcl.AsyncInterfaces (8.0)
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1))
Microsoft.Bcl.TimeProvider (8.0)
Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0))
Expand Down
21 changes: 5 additions & 16 deletions src/IcedTasks/AsyncEx.fs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ type AsyncEx =
)
|> ignore
)
#if NETSTANDARD2_1 || NET6_0_OR_GREATER


/// <summary>
Expand Down Expand Up @@ -191,7 +190,6 @@ type AsyncEx =
else
AsyncEx.AwaitTask(vTask.AsTask())

#endif

/// <exclude/>
[<AutoOpen>]
Expand Down Expand Up @@ -274,19 +272,13 @@ type AsyncExBuilder() =
member inline _.Bind(computation: Async<'f>, [<InlineIfLambda>] binder: 'f -> Async<'f0>) =
async.Bind(computation, binder)

#if NETSTANDARD2_1 || NET6_0_OR_GREATER

member inline _.TryFinallyAsync
member inline this.TryFinallyAsync
(
computation: Async<'ok>,
[<InlineIfLambda>] compensation: unit -> ValueTask
) : Async<'ok> =

let compensation =
async {
let vTask = compensation ()
return! Async.AwaitValueTask vTask
}
let compensation = this.Delay(fun () -> AsyncEx.AwaitValueTask(compensation ()))

Async.TryFinallyAsync(computation, compensation)

Expand Down Expand Up @@ -331,14 +323,13 @@ type AsyncExBuilder() =
enumerator.MoveNextAsync()
|> AsyncEx.AwaitValueTask
)),
(body enumerator.Current)
(this.Delay(fun () -> body enumerator.Current))
)

)
)
)

#endif
member inline _.While([<InlineIfLambda>] guard: unit -> bool, computation: Async<unit>) =
async.While(guard, computation)

Expand Down Expand Up @@ -412,9 +403,8 @@ module AsyncExExtensionsHighPriority =

type AsyncExBuilder with

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
member inline _.Source(seq: #IAsyncEnumerable<_>) = seq
#endif

// Required because SRTP can't determine the type of the awaiter
// Candidates:
// - Task.GetAwaiter() : Runtime.CompilerServices.TaskAwaiter
Expand All @@ -423,11 +413,10 @@ module AsyncExExtensionsHighPriority =

member inline _.Source(task: Task) = AsyncEx.AwaitTask task

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
member inline _.Source(vtask: ValueTask<_>) = AsyncEx.AwaitValueTask vtask

member inline _.Source(vtask: ValueTask) = AsyncEx.AwaitValueTask vtask
#endif

namespace IcedTasks.Polyfill.Async

/// <namespacedoc>
Expand Down
7 changes: 1 addition & 6 deletions src/IcedTasks/CancellableTask.fs
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,7 @@ module CancellableTasks =
/// followed by "Tasks Finished".
/// </example>
let inline getCancellationToken () =
fun (ct: CancellationToken) ->
#if NETSTANDARD2_1 || NET6_0_OR_GREATER
ValueTask<CancellationToken> ct
#else
Task.FromResult ct
#endif
fun (ct: CancellationToken) -> ValueTask<CancellationToken> ct

/// <summary>Lifts an item to a CancellableTask.</summary>
/// <param name="item">The item to be the result of the CancellableTask.</param>
Expand Down
6 changes: 1 addition & 5 deletions src/IcedTasks/CancellableTaskBuilderBase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ module CancellableTaskBase =
body: 'T -> CancellableTaskBaseCode<'TOverall, unit, 'Builder>
) : CancellableTaskBaseCode<'TOverall, unit, 'Builder> =
ResumableCode.For(sequence, body)
#if NETSTANDARD2_1 || NET6_0_OR_GREATER

/// <summary>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.</summary>
Expand Down Expand Up @@ -379,8 +379,6 @@ module CancellableTaskBase =
)
.Invoke(&sm)
)
#endif


/// <exclude/>
[<AutoOpen>]
Expand Down Expand Up @@ -764,14 +762,12 @@ module CancellableTaskBase =
// High priority extensions
type CancellableTaskBuilderBase with

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
/// <summary>Allows the computation expression to turn other types into other types</summary>
///
/// <remarks>This is the identify function for For binds.</remarks>
///
/// <returns>IEnumerable</returns>
member inline _.Source(s: #IAsyncEnumerable<_>) = s
#endif

/// <summary>Allows the computation expression to turn other types into CancellationToken -> 'Awaiter</summary>
///
Expand Down
2 changes: 0 additions & 2 deletions src/IcedTasks/CancellableValueTask.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace IcedTasks

#if NETSTANDARD2_1 || NET6_0_OR_GREATER

/// Contains methods to build CancellableTasks using the F# computation expression syntax
[<AutoOpen>]
Expand Down Expand Up @@ -456,4 +455,3 @@ module CancellableValueTasks =
fun ct ->
cancellableTask ct
|> ValueTask.toUnit
#endif
2 changes: 0 additions & 2 deletions src/IcedTasks/ColdTask.fs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ module ColdTasks =
) : ColdTaskCode<'TOverall, unit> =
ResumableCode.For(sequence, body)

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
/// <summary>Creates an ColdTask 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.</summary>
Expand Down Expand Up @@ -287,7 +286,6 @@ module ColdTasks =
)
)

#endif
/// Contains methods to build ColdTasks using the F# computation expression syntax
type ColdTaskBuilder() =

Expand Down
4 changes: 0 additions & 4 deletions src/IcedTasks/TaskBuilderBase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ module TaskBase =
)
)

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
/// <summary>Creates a Task 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.</summary>
Expand Down Expand Up @@ -345,7 +344,6 @@ module TaskBase =
)
.Invoke(&sm)
)
#endif

/// <summary>Creates a Task that enumerates the sequence seq
/// on demand and runs body for each element.</summary>
Expand Down Expand Up @@ -550,14 +548,12 @@ module TaskBase =
// High priority extensions
type TaskBuilderBase with

#if NETSTANDARD2_1 || NET6_0_OR_GREATER
/// <summary>Allows the computation expression to turn other types into other types</summary>
///
/// <remarks>This is the identify function for For binds.</remarks>
///
/// <returns>IEnumerable</returns>
member inline _.Source(s: #IAsyncEnumerable<_>) = s
#endif


/// <summary>Allows the computation expression to turn other types into 'Awaiter</summary>
Expand Down
21 changes: 18 additions & 3 deletions src/IcedTasks/TaskUnit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module TasksUnit =
/// <summary>
/// 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.
/// </summary>
static member inline RunDynamic(code: TaskBaseCode<'T, 'T, _>) : Task =
static member inline RunDynamic(code: TaskBaseCode<'T, 'T, AsyncTaskMethodBuilder>) : Task =

let mutable sm = TaskBaseStateMachine<'T, _>()

Expand All @@ -58,7 +58,12 @@ module TasksUnit =
let step = info.ResumptionFunc.Invoke(&sm)

if step then
#if DEBUG
sm.Data.MethodBuilder.SetResult()
#else
// SRTP fails here for some reason in debug mode
MethodBuilder.SetResult(&sm.Data.MethodBuilder)
#endif
else
let mutable awaiter =
sm.ResumptionDynamicInfo.ResumptionData
Expand Down Expand Up @@ -89,7 +94,7 @@ module TasksUnit =
MethodBuilder.get_Task (&sm.Data.MethodBuilder)

/// Hosts the task code in a state machine and starts the task.
member inline _.Run(code: TaskBaseCode<'T, 'T, _>) : Task =
member inline _.Run(code: TaskBaseCode<'T, 'T, AsyncTaskMethodBuilder>) : Task =
if __useResumableCode then
__stateMachine<TaskBaseStateMachineData<'T, _>, _>
(MoveNextMethodImpl<_>(fun sm ->
Expand All @@ -101,7 +106,12 @@ module TasksUnit =
let __stack_code_fin = code.Invoke(&sm)

if __stack_code_fin then
#if DEBUG
sm.Data.MethodBuilder.SetResult()
#else
// SRTP fails here for some reason in debug mode
MethodBuilder.SetResult(&sm.Data.MethodBuilder)
#endif
with exn ->
__stack_exn <- exn
// Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567
Expand Down Expand Up @@ -157,7 +167,7 @@ module TasksUnit =
/// <summary>
/// Hosts the task code in a state machine and starts the task, executing in the threadpool using Task.Run
/// </summary>
member inline _.Run(code: TaskBaseCode<'T, 'T, _>) =
member inline _.Run(code: TaskBaseCode<'T, 'T, AsyncTaskMethodBuilder>) =
if __useResumableCode then
__stateMachine<TaskBaseStateMachineData<'T, _>, _>
(MoveNextMethodImpl<_>(fun sm ->
Expand All @@ -169,7 +179,12 @@ module TasksUnit =
let __stack_code_fin = code.Invoke(&sm)

if __stack_code_fin then
#if DEBUG
sm.Data.MethodBuilder.SetResult()
#else
// SRTP fails here for some reason in debug mode
MethodBuilder.SetResult(&sm.Data.MethodBuilder)
#endif
with exn ->
__stack_exn <- exn
// Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567
Expand Down
4 changes: 0 additions & 4 deletions src/IcedTasks/ValueTask.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ namespace IcedTasks

open System.Threading.Tasks

#if NETSTANDARD2_1 || NET6_0_OR_GREATER

/// <summary>
/// Module with extension methods for <see cref="T:System.Threading.Tasks.ValueTask`1"/>.
Expand Down Expand Up @@ -310,6 +309,3 @@ module ValueTasks =
ValueTask()
else
ValueTask(vtask.AsTask())


#endif
23 changes: 16 additions & 7 deletions src/IcedTasks/ValueTaskUnit.fs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
namespace IcedTasks


#if NETSTANDARD2_1 || NET6_0_OR_GREATER

// Task builder for F# that compiles to allocation-free paths for synchronous code.
//
// Originally written in 2016 by Robert Peele ([email protected])
Expand Down Expand Up @@ -43,7 +41,9 @@ module ValueTasksUnit =
/// <summary>
/// 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.
/// </summary>
static member inline RunDynamic(code: TaskBaseCode<'T, 'T, _>) : ValueTask =
static member inline RunDynamic
(code: TaskBaseCode<'T, 'T, AsyncValueTaskMethodBuilder>)
: ValueTask =

let mutable sm = TaskBaseStateMachine<'T, _>()

Expand All @@ -60,7 +60,12 @@ module ValueTasksUnit =
let step = info.ResumptionFunc.Invoke(&sm)

if step then
#if DEBUG
sm.Data.MethodBuilder.SetResult()
#else
// SRTP fails here for some reason in debug mode
MethodBuilder.SetResult(&sm.Data.MethodBuilder)
#endif
else
let mutable awaiter =
sm.ResumptionDynamicInfo.ResumptionData
Expand All @@ -82,6 +87,7 @@ module ValueTasksUnit =
| exn -> MethodBuilder.SetException(&sm.Data.MethodBuilder, exn)

member _.SetStateMachine(sm, state) =

MethodBuilder.SetStateMachine(&sm.Data.MethodBuilder, state)
}

Expand All @@ -91,9 +97,9 @@ module ValueTasksUnit =
MethodBuilder.get_Task (&sm.Data.MethodBuilder)

/// Hosts the task code in a state machine and starts the task.
member inline _.Run(code: TaskBaseCode<'T, 'T, _>) : ValueTask =
member inline _.Run(code: TaskBaseCode<'T, 'T, AsyncValueTaskMethodBuilder>) : ValueTask =
if __useResumableCode then
__stateMachine<TaskBaseStateMachineData<'T, _>, ValueTask>
__stateMachine<TaskBaseStateMachineData<'T, AsyncValueTaskMethodBuilder>, ValueTask>
(MoveNextMethodImpl<_>(fun sm ->
//-- RESUMABLE CODE START
__resumeAt sm.ResumptionPoint
Expand All @@ -103,7 +109,12 @@ module ValueTasksUnit =
let __stack_code_fin = code.Invoke(&sm)

if __stack_code_fin then
#if DEBUG
sm.Data.MethodBuilder.SetResult()
#else
// SRTP fails here for some reason in debug mode
MethodBuilder.SetResult(&sm.Data.MethodBuilder)
#endif
with exn ->
__stack_exn <- exn
// Run SetException outside the stack unwind, see https://github.com/dotnet/roslyn/issues/26567
Expand Down Expand Up @@ -148,5 +159,3 @@ module ValueTasksUnit =
/// Builds a valueTask using computation expression syntax.
/// </summary>
let vTaskUnit = valueTaskUnit

#endif
Loading

0 comments on commit 2090b7c

Please sign in to comment.