You've already forked linux-packaging-mono
Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
parent
1190d13a04
commit
6bdd276d05
31
external/corefx/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln
vendored
Normal file
31
external/corefx/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions.Tests", "tests\System.Threading.Tasks.Extensions.Tests.csproj", "{82B54697-0251-47A1-8546-FC507D0F3B08}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{} = {}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions", "src\System.Threading.Tasks.Extensions.csproj", "{F24D3391-2928-4E83-AADE-B34423498750}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU = DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU
|
||||
ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU = ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{82B54697-0251-47A1-8546-FC507D0F3B08}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Debug|Any CPU
|
||||
{82B54697-0251-47A1-8546-FC507D0F3B08}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Debug|Any CPU
|
||||
{82B54697-0251-47A1-8546-FC507D0F3B08}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Release|Any CPU
|
||||
{82B54697-0251-47A1-8546-FC507D0F3B08}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Release|Any CPU
|
||||
{F24D3391-2928-4E83-AADE-B34423498750}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.0-Debug|Any CPU
|
||||
{F24D3391-2928-4E83-AADE-B34423498750}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.0-Debug|Any CPU
|
||||
{F24D3391-2928-4E83-AADE-B34423498750}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.0-Release|Any CPU
|
||||
{F24D3391-2928-4E83-AADE-B34423498750}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.0-Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
8
external/corefx/src/System.Threading.Tasks.Extensions/dir.props
vendored
Normal file
8
external/corefx/src/System.Threading.Tasks.Extensions/dir.props
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\dir.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyVersion>4.1.1.0</AssemblyVersion>
|
||||
<IsNETCoreApp>true</IsNETCoreApp>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<ItemGroup>
|
||||
<Project Include="System.Threading.Tasks.Extensions.pkgproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<PropertyGroup>
|
||||
<!-- we need to be supported on pre-nuget-3 platforms (Dev12, Dev11, etc) -->
|
||||
<MinClientVersion>2.8.6</MinClientVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\src\System.Threading.Tasks.Extensions.builds">
|
||||
<SupportedFramework>net45;netcore45;netcoreapp1.0;wpa81;wp8;$(AllXamarinFrameworks)</SupportedFramework>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
9
external/corefx/src/System.Threading.Tasks.Extensions/src/Configurations.props
vendored
Normal file
9
external/corefx/src/System.Threading.Tasks.Extensions/src/Configurations.props
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netstandard1.0;
|
||||
netcoreapp;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{F24D3391-2928-4E83-AADE-B34423498750}</ProjectGuid>
|
||||
<AssemblyName>System.Threading.Tasks.Extensions</AssemblyName>
|
||||
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
|
||||
<UseOpenKey Condition="'$(UseOpenKey)'==''">true</UseOpenKey>
|
||||
<PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard1.0'">netstandard1.0;portable-net45+win8+wp8+wpa81</PackageTargetFramework>
|
||||
</PropertyGroup>
|
||||
<!-- Default configurations to help VS understand the configurations -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.0-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.0-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs" />
|
||||
<Compile Include="System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs" />
|
||||
<Compile Include="System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs" />
|
||||
<Compile Include="System\Runtime\CompilerServices\ValueTaskAwaiter.cs" />
|
||||
<Compile Include="System\Threading\Tasks\ValueTask.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Collections" />
|
||||
<Reference Include="System.Diagnostics.Debug" />
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,24 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of the async method builder that should be used by a language compiler to
|
||||
/// build the attributed type when used as the return type of an async method.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class AsyncMethodBuilderAttribute : Attribute
|
||||
{
|
||||
/// <summary>Initializes the <see cref="AsyncMethodBuilderAttribute"/>.</summary>
|
||||
/// <param name="builderType">The <see cref="Type"/> of the associated builder.</param>
|
||||
public AsyncMethodBuilderAttribute(Type builderType)
|
||||
{
|
||||
BuilderType = builderType;
|
||||
}
|
||||
|
||||
/// <summary>Gets the <see cref="Type"/> of the associated builder.</summary>
|
||||
public Type BuilderType { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
|
||||
/// <typeparam name="TResult">The type of the result.</typeparam>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct AsyncValueTaskMethodBuilder<TResult>
|
||||
{
|
||||
/// <summary>The <see cref="AsyncTaskMethodBuilder{TResult}"/> to which most operations are delegated.</summary>
|
||||
private AsyncTaskMethodBuilder<TResult> _methodBuilder;
|
||||
/// <summary>The result for this builder, if it's completed before any awaits occur.</summary>
|
||||
private TResult _result;
|
||||
/// <summary>true if <see cref="_result"/> contains the synchronous result for the async method; otherwise, false.</summary>
|
||||
private bool _haveResult;
|
||||
/// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
|
||||
private bool _useBuilder;
|
||||
|
||||
/// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder{TResult}"/> struct.</summary>
|
||||
/// <returns>The initialized instance.</returns>
|
||||
public static AsyncValueTaskMethodBuilder<TResult> Create() =>
|
||||
new AsyncValueTaskMethodBuilder<TResult>() { _methodBuilder = AsyncTaskMethodBuilder<TResult>.Create() };
|
||||
|
||||
/// <summary>Begins running the builder with the associated state machine.</summary>
|
||||
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
|
||||
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
|
||||
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
_methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
|
||||
}
|
||||
|
||||
/// <summary>Associates the builder with the specified state machine.</summary>
|
||||
/// <param name="stateMachine">The state machine instance to associate with the builder.</param>
|
||||
public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
|
||||
|
||||
/// <summary>Marks the task as successfully completed.</summary>
|
||||
/// <param name="result">The result to use to complete the task.</param>
|
||||
public void SetResult(TResult result)
|
||||
{
|
||||
if (_useBuilder)
|
||||
{
|
||||
_methodBuilder.SetResult(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_result = result;
|
||||
_haveResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
|
||||
/// <param name="exception">The exception to bind to the task.</param>
|
||||
public void SetException(Exception exception) => _methodBuilder.SetException(exception);
|
||||
|
||||
/// <summary>Gets the task for this builder.</summary>
|
||||
public ValueTask<TResult> Task
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_haveResult)
|
||||
{
|
||||
return new ValueTask<TResult>(_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_useBuilder = true;
|
||||
return new ValueTask<TResult>(_methodBuilder.Task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
|
||||
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
|
||||
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
|
||||
/// <param name="awaiter">the awaiter</param>
|
||||
/// <param name="stateMachine">The state machine.</param>
|
||||
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
||||
where TAwaiter : INotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
_useBuilder = true;
|
||||
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
|
||||
}
|
||||
|
||||
/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
|
||||
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
|
||||
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
|
||||
/// <param name="awaiter">the awaiter</param>
|
||||
/// <param name="stateMachine">The state machine.</param>
|
||||
[SecuritySafeCritical]
|
||||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
||||
where TAwaiter : ICriticalNotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
_useBuilder = true;
|
||||
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary>
|
||||
/// <typeparam name="TResult">The type of the result produced.</typeparam>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct ConfiguredValueTaskAwaitable<TResult>
|
||||
{
|
||||
/// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary>
|
||||
private readonly ValueTask<TResult> _value;
|
||||
/// <summary>true to attempt to marshal the continuation back to the original context captured; otherwise, false.</summary>
|
||||
private readonly bool _continueOnCapturedContext;
|
||||
|
||||
/// <summary>Initializes the awaitable.</summary>
|
||||
/// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param>
|
||||
/// <param name="continueOnCapturedContext">
|
||||
/// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
|
||||
/// </param>
|
||||
internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value, bool continueOnCapturedContext)
|
||||
{
|
||||
_value = value;
|
||||
_continueOnCapturedContext = continueOnCapturedContext;
|
||||
}
|
||||
|
||||
/// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary>
|
||||
public ConfiguredValueTaskAwaiter GetAwaiter()
|
||||
{
|
||||
return new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
|
||||
}
|
||||
|
||||
/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
/// <summary>The value being awaited.</summary>
|
||||
private readonly ValueTask<TResult> _value;
|
||||
/// <summary>The value to pass to ConfigureAwait.</summary>
|
||||
private readonly bool _continueOnCapturedContext;
|
||||
|
||||
/// <summary>Initializes the awaiter.</summary>
|
||||
/// <param name="value">The value to be awaited.</param>
|
||||
/// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param>
|
||||
internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCapturedContext)
|
||||
{
|
||||
_value = value;
|
||||
_continueOnCapturedContext = continueOnCapturedContext;
|
||||
}
|
||||
|
||||
/// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{TResult}"/> has completed.</summary>
|
||||
public bool IsCompleted { get { return _value.IsCompleted; } }
|
||||
|
||||
/// <summary>Gets the result of the ValueTask.</summary>
|
||||
public TResult GetResult()
|
||||
{
|
||||
return _value._task == null ?
|
||||
_value._result :
|
||||
_value._task.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
|
||||
}
|
||||
|
||||
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary>
|
||||
public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion
|
||||
{
|
||||
/// <summary>The value being awaited.</summary>
|
||||
private readonly ValueTask<TResult> _value;
|
||||
|
||||
/// <summary>Initializes the awaiter.</summary>
|
||||
/// <param name="value">The value to be awaited.</param>
|
||||
internal ValueTaskAwaiter(ValueTask<TResult> value) { _value = value; }
|
||||
|
||||
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary>
|
||||
public bool IsCompleted { get { return _value.IsCompleted; } }
|
||||
|
||||
/// <summary>Gets the result of the ValueTask.</summary>
|
||||
public TResult GetResult()
|
||||
{
|
||||
return _value._task == null ?
|
||||
_value._result :
|
||||
_value._task.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>Schedules the continuation action for this ValueTask.</summary>
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
_value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation);
|
||||
}
|
||||
|
||||
/// <summary>Schedules the continuation action for this ValueTask.</summary>
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
_value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
187
external/corefx/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs
vendored
Normal file
187
external/corefx/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Threading.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a value type that wraps a <see cref="Task{TResult}"/> and a <typeparamref name="TResult"/>,
|
||||
/// only one of which is used.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">The type of the result.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Methods may return an instance of this value type when it's likely that the result of their
|
||||
/// operations will be available synchronously and when the method is expected to be invoked so
|
||||
/// frequently that the cost of allocating a new <see cref="Task{TResult}"/> for each call will
|
||||
/// be prohibitive.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// There are tradeoffs to using a <see cref="ValueTask{TResult}"/> instead of a <see cref="Task{TResult}"/>.
|
||||
/// For example, while a <see cref="ValueTask{TResult}"/> can help avoid an allocation in the case where the
|
||||
/// successful result is available synchronously, it also contains two fields whereas a <see cref="Task{TResult}"/>
|
||||
/// as a reference type is a single field. This means that a method call ends up returning two fields worth of
|
||||
/// data instead of one, which is more data to copy. It also means that if a method that returns one of these
|
||||
/// is awaited within an async method, the state machine for that async method will be larger due to needing
|
||||
/// to store the struct that's two fields instead of a single reference.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Further, for uses other than consuming the result of an asynchronous operation via await,
|
||||
/// <see cref="ValueTask{TResult}"/> can lead to a more convoluted programming model, which can in turn actually
|
||||
/// lead to more allocations. For example, consider a method that could return either a <see cref="Task{TResult}"/>
|
||||
/// with a cached task as a common result or a <see cref="ValueTask{TResult}"/>. If the consumer of the result
|
||||
/// wants to use it as a <see cref="Task{TResult}"/>, such as to use with in methods like Task.WhenAll and Task.WhenAny,
|
||||
/// the <see cref="ValueTask{TResult}"/> would first need to be converted into a <see cref="Task{TResult}"/> using
|
||||
/// <see cref="ValueTask{TResult}.AsTask"/>, which leads to an allocation that would have been avoided if a cached
|
||||
/// <see cref="Task{TResult}"/> had been used in the first place.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// As such, the default choice for any asynchronous method should be to return a <see cref="Task"/> or
|
||||
/// <see cref="Task{TResult}"/>. Only if performance analysis proves it worthwhile should a <see cref="ValueTask{TResult}"/>
|
||||
/// be used instead of <see cref="Task{TResult}"/>. There is no non-generic version of <see cref="ValueTask{TResult}"/>
|
||||
/// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where
|
||||
/// a <see cref="Task"/>-returning method completes synchronously and successfully.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
|
||||
{
|
||||
/// <summary>The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully.</summary>
|
||||
internal readonly Task<TResult> _task;
|
||||
/// <summary>The result to be used if the operation completed successfully synchronously.</summary>
|
||||
internal readonly TResult _result;
|
||||
|
||||
/// <summary>Initialize the <see cref="ValueTask{TResult}"/> with the result of the successful operation.</summary>
|
||||
/// <param name="result">The result.</param>
|
||||
public ValueTask(TResult result)
|
||||
{
|
||||
_task = null;
|
||||
_result = result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="Task{TResult}"/> that represents the operation.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
public ValueTask(Task<TResult> task)
|
||||
{
|
||||
if (task == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(task));
|
||||
}
|
||||
|
||||
_task = task;
|
||||
_result = default(TResult);
|
||||
}
|
||||
|
||||
/// <summary>Returns the hash code for this instance.</summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return
|
||||
_task != null ? _task.GetHashCode() :
|
||||
_result != null ? _result.GetHashCode() :
|
||||
0;
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return
|
||||
obj is ValueTask<TResult> &&
|
||||
Equals((ValueTask<TResult>)obj);
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ValueTask{TResult}"/> value.</summary>
|
||||
public bool Equals(ValueTask<TResult> other)
|
||||
{
|
||||
return _task != null || other._task != null ?
|
||||
_task == other._task :
|
||||
EqualityComparer<TResult>.Default.Equals(_result, other._result);
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are equal.</summary>
|
||||
public static bool operator==(ValueTask<TResult> left, ValueTask<TResult> right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are not equal.</summary>
|
||||
public static bool operator!=(ValueTask<TResult> left, ValueTask<TResult> right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask. It will
|
||||
/// either return the wrapped task object if one exists, or it'll manufacture a new
|
||||
/// task object to represent the result.
|
||||
/// </summary>
|
||||
public Task<TResult> AsTask()
|
||||
{
|
||||
// Return the task if we were constructed from one, otherwise manufacture one. We don't
|
||||
// cache the generated task into _task as it would end up changing both equality comparison
|
||||
// and the hash code we generate in GetHashCode.
|
||||
return _task ?? Task.FromResult(_result);
|
||||
}
|
||||
|
||||
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary>
|
||||
public bool IsCompleted { get { return _task == null || _task.IsCompleted; } }
|
||||
|
||||
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a successfully completed operation.</summary>
|
||||
public bool IsCompletedSuccessfully { get { return _task == null || _task.Status == TaskStatus.RanToCompletion; } }
|
||||
|
||||
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a failed operation.</summary>
|
||||
public bool IsFaulted { get { return _task != null && _task.IsFaulted; } }
|
||||
|
||||
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a canceled operation.</summary>
|
||||
public bool IsCanceled { get { return _task != null && _task.IsCanceled; } }
|
||||
|
||||
/// <summary>Gets the result.</summary>
|
||||
public TResult Result { get { return _task == null ? _result : _task.GetAwaiter().GetResult(); } }
|
||||
|
||||
/// <summary>Gets an awaiter for this value.</summary>
|
||||
public ValueTaskAwaiter<TResult> GetAwaiter()
|
||||
{
|
||||
return new ValueTaskAwaiter<TResult>(this);
|
||||
}
|
||||
|
||||
/// <summary>Configures an awaiter for this value.</summary>
|
||||
/// <param name="continueOnCapturedContext">
|
||||
/// true to attempt to marshal the continuation back to the captured context; otherwise, false.
|
||||
/// </param>
|
||||
public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
|
||||
{
|
||||
return new ConfiguredValueTaskAwaitable<TResult>(this, continueOnCapturedContext: continueOnCapturedContext);
|
||||
}
|
||||
|
||||
/// <summary>Gets a string-representation of this <see cref="ValueTask{TResult}"/>.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
if (_task != null)
|
||||
{
|
||||
return _task.Status == TaskStatus.RanToCompletion && _task.Result != null ?
|
||||
_task.Result.ToString() :
|
||||
string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _result != null ?
|
||||
_result.ToString() :
|
||||
string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute.
|
||||
|
||||
/// <summary>Creates a method builder for use with an async method.</summary>
|
||||
/// <returns>The created builder.</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption
|
||||
public static AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder<TResult>.Create();
|
||||
}
|
||||
}
|
||||
40
external/corefx/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs
vendored
Normal file
40
external/corefx/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace System.Runtime.CompilerServices.Tests
|
||||
{
|
||||
public class AsyncMethodBuilderAttributeTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(typeof(string))]
|
||||
[InlineData(typeof(int))]
|
||||
[InlineData(typeof(AsyncValueTaskMethodBuilder<>))]
|
||||
[InlineData(typeof(AsyncValueTaskMethodBuilder<int>))]
|
||||
[InlineData(typeof(AsyncValueTaskMethodBuilder<string>))]
|
||||
public void Ctor_BuilderType_Roundtrip(Type builderType)
|
||||
{
|
||||
var amba = new AsyncMethodBuilderAttribute(builderType);
|
||||
Assert.Same(builderType, amba.BuilderType);
|
||||
}
|
||||
|
||||
// No tests for the following, other than verifying that they successfully compile
|
||||
|
||||
[AsyncMethodBuilder(typeof(string))]
|
||||
class MyClass { }
|
||||
|
||||
[AsyncMethodBuilder(typeof(string))]
|
||||
struct MyStruct { }
|
||||
|
||||
[AsyncMethodBuilder(typeof(string))]
|
||||
interface MyInterface { }
|
||||
|
||||
[AsyncMethodBuilder(typeof(string))]
|
||||
enum MyEnum { }
|
||||
|
||||
[AsyncMethodBuilder(typeof(string))]
|
||||
delegate void MyDelegate();
|
||||
}
|
||||
}
|
||||
219
external/corefx/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
vendored
Normal file
219
external/corefx/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class AsyncValueTaskMethodBuilderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Create_ReturnsDefaultInstance()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
Assert.Equal(default(AsyncValueTaskMethodBuilder<int>), b); // implementation detail being verified
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetResult_BeforeAccessTask_ValueTaskContainsValue()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
b.SetResult(42);
|
||||
ValueTask<int> vt = b.Task;
|
||||
Assert.True(vt.IsCompletedSuccessfully);
|
||||
Assert.False(WrapsTask(vt));
|
||||
Assert.Equal(42, vt.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetResult_AfterAccessTask_ValueTaskContainsValue()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
ValueTask<int> vt = b.Task;
|
||||
b.SetResult(42);
|
||||
Assert.True(vt.IsCompletedSuccessfully);
|
||||
Assert.True(WrapsTask(vt));
|
||||
Assert.Equal(42, vt.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetException_BeforeAccessTask_FaultsTask()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
var e = new FormatException();
|
||||
b.SetException(e);
|
||||
ValueTask<int> vt = b.Task;
|
||||
Assert.True(vt.IsFaulted);
|
||||
Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetException_AfterAccessTask_FaultsTask()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
var e = new FormatException();
|
||||
ValueTask<int> vt = b.Task;
|
||||
b.SetException(e);
|
||||
Assert.True(vt.IsFaulted);
|
||||
Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetException_OperationCanceledException_CancelsTask()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
var e = new OperationCanceledException();
|
||||
ValueTask<int> vt = b.Task;
|
||||
b.SetException(e);
|
||||
Assert.True(vt.IsCanceled);
|
||||
Assert.Same(e, Assert.Throws<OperationCanceledException>(() => vt.GetAwaiter().GetResult()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Start_InvokesMoveNext()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
int invokes = 0;
|
||||
var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
|
||||
b.Start(ref dsm);
|
||||
Assert.Equal(1, invokes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task AwaitOnCompleted_InvokesStateMachineMethods(bool awaitUnsafe)
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
var ignored = b.Task;
|
||||
|
||||
var callbackCompleted = new TaskCompletionSource<bool>();
|
||||
IAsyncStateMachine foundSm = null;
|
||||
var dsm = new DelegateStateMachine
|
||||
{
|
||||
MoveNextDelegate = () => callbackCompleted.SetResult(true),
|
||||
SetStateMachineDelegate = sm => foundSm = sm
|
||||
};
|
||||
|
||||
TaskAwaiter t = Task.CompletedTask.GetAwaiter();
|
||||
if (awaitUnsafe)
|
||||
{
|
||||
b.AwaitUnsafeOnCompleted(ref t, ref dsm);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.AwaitOnCompleted(ref t, ref dsm);
|
||||
}
|
||||
|
||||
await callbackCompleted.Task;
|
||||
Assert.Equal(dsm, foundSm);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1, false)]
|
||||
[InlineData(2, false)]
|
||||
[InlineData(1, true)]
|
||||
[InlineData(2, true)]
|
||||
public void AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
|
||||
var dsm = new DelegateStateMachine();
|
||||
TaskAwaiter<int> t = new TaskCompletionSource<int>().Task.GetAwaiter();
|
||||
|
||||
Assert.InRange(numAwaits, 1, int.MaxValue);
|
||||
for (int i = 1; i <= numAwaits; i++)
|
||||
{
|
||||
if (awaitUnsafe)
|
||||
{
|
||||
b.AwaitUnsafeOnCompleted(ref t, ref dsm);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.AwaitOnCompleted(ref t, ref dsm);
|
||||
}
|
||||
}
|
||||
|
||||
b.SetResult(42);
|
||||
|
||||
Assert.True(WrapsTask(b.Task));
|
||||
Assert.Equal(42, b.Task.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetStateMachine_InvalidArgument_ThrowsException()
|
||||
{
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
Assert.Throws<ArgumentNullException>("stateMachine", () => b.SetStateMachine(null));
|
||||
b.SetStateMachine(new DelegateStateMachine());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Start_ExecutionContextChangesInMoveNextDontFlowOut()
|
||||
{
|
||||
var al = new AsyncLocal<int> { Value = 0 };
|
||||
int calls = 0;
|
||||
|
||||
var dsm = new DelegateStateMachine
|
||||
{
|
||||
MoveNextDelegate = () =>
|
||||
{
|
||||
al.Value++;
|
||||
calls++;
|
||||
}
|
||||
};
|
||||
|
||||
dsm.MoveNext();
|
||||
Assert.Equal(1, al.Value);
|
||||
Assert.Equal(1, calls);
|
||||
|
||||
dsm.MoveNext();
|
||||
Assert.Equal(2, al.Value);
|
||||
Assert.Equal(2, calls);
|
||||
|
||||
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
|
||||
b.Start(ref dsm);
|
||||
Assert.Equal(2, al.Value); // change should not be visible
|
||||
Assert.Equal(3, calls);
|
||||
|
||||
// Make sure we've not caused the Task to be allocated
|
||||
b.SetResult(42);
|
||||
ValueTask<int> vt = b.Task;
|
||||
Assert.False(WrapsTask(vt));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(10)]
|
||||
public static async Task UsedWithAsyncMethod_CompletesSuccessfully(int yields)
|
||||
{
|
||||
Assert.Equal(42, await ValueTaskReturningAsyncMethod(42));
|
||||
|
||||
ValueTask<int> vt = ValueTaskReturningAsyncMethod(84);
|
||||
Assert.Equal(yields > 0, WrapsTask(vt));
|
||||
Assert.Equal(84, await vt);
|
||||
|
||||
async ValueTask<int> ValueTaskReturningAsyncMethod(int result)
|
||||
{
|
||||
for (int i = 0; i < yields; i++) await Task.Yield();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets whether the ValueTask has a non-null Task.</summary>
|
||||
private static bool WrapsTask<T>(ValueTask<T> vt) => ReferenceEquals(vt.AsTask(), vt.AsTask());
|
||||
|
||||
private struct DelegateStateMachine : IAsyncStateMachine
|
||||
{
|
||||
internal Action MoveNextDelegate;
|
||||
public void MoveNext() => MoveNextDelegate?.Invoke();
|
||||
|
||||
internal Action<IAsyncStateMachine> SetStateMachineDelegate;
|
||||
public void SetStateMachine(IAsyncStateMachine stateMachine) => SetStateMachineDelegate?.Invoke(stateMachine);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
external/corefx/src/System.Threading.Tasks.Extensions/tests/Configurations.props
vendored
Normal file
8
external/corefx/src/System.Threading.Tasks.Extensions/tests/Configurations.props
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netstandard1.3;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<ItemGroup>
|
||||
<Project Include="System.Threading.Tasks.Extensions.Tests.csproj" />
|
||||
<Project Include="System.Threading.Tasks.Extensions.Tests.csproj">
|
||||
<OSGroup>Windows_NT</OSGroup>
|
||||
<TestTFMs>netcore50;net46</TestTFMs>
|
||||
</Project>
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{82B54697-0251-47A1-8546-FC507D0F3B08}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="AsyncMethodBuilderAttributeTests.cs" />
|
||||
<Compile Include="AsyncValueTaskMethodBuilderTests.cs" />
|
||||
<Compile Include="ValueTaskTests.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
342
external/corefx/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs
vendored
Normal file
342
external/corefx/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class ValueTaskTests
|
||||
{
|
||||
[Fact]
|
||||
public void DefaultValueTask_ValueType_DefaultValue()
|
||||
{
|
||||
Assert.True(default(ValueTask<int>).IsCompleted);
|
||||
Assert.True(default(ValueTask<int>).IsCompletedSuccessfully);
|
||||
Assert.False(default(ValueTask<int>).IsFaulted);
|
||||
Assert.False(default(ValueTask<int>).IsCanceled);
|
||||
Assert.Equal(0, default(ValueTask<int>).Result);
|
||||
|
||||
Assert.True(default(ValueTask<string>).IsCompleted);
|
||||
Assert.True(default(ValueTask<string>).IsCompletedSuccessfully);
|
||||
Assert.False(default(ValueTask<string>).IsFaulted);
|
||||
Assert.False(default(ValueTask<string>).IsCanceled);
|
||||
Assert.Equal(null, default(ValueTask<string>).Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromValue_IsRanToCompletion()
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
Assert.True(t.IsCompleted);
|
||||
Assert.True(t.IsCompletedSuccessfully);
|
||||
Assert.False(t.IsFaulted);
|
||||
Assert.False(t.IsCanceled);
|
||||
Assert.Equal(42, t.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromCompletedTask_IsRanToCompletion()
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(Task.FromResult(42));
|
||||
Assert.True(t.IsCompleted);
|
||||
Assert.True(t.IsCompletedSuccessfully);
|
||||
Assert.False(t.IsFaulted);
|
||||
Assert.False(t.IsCanceled);
|
||||
Assert.Equal(42, t.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromNotCompletedTask_IsNotRanToCompletion()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<int>();
|
||||
ValueTask<int> t = new ValueTask<int>(tcs.Task);
|
||||
|
||||
Assert.False(t.IsCompleted);
|
||||
Assert.False(t.IsCompletedSuccessfully);
|
||||
Assert.False(t.IsFaulted);
|
||||
Assert.False(t.IsCanceled);
|
||||
|
||||
tcs.SetResult(42);
|
||||
|
||||
Assert.Equal(42, t.Result);
|
||||
Assert.True(t.IsCompleted);
|
||||
Assert.True(t.IsCompletedSuccessfully);
|
||||
Assert.False(t.IsFaulted);
|
||||
Assert.False(t.IsCanceled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromNullTask_Throws()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new ValueTask<int>((Task<int>)null));
|
||||
Assert.Throws<ArgumentNullException>(() => new ValueTask<string>((Task<string>)null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromTask_AsTaskIdempotent()
|
||||
{
|
||||
Task<int> source = Task.FromResult(42);
|
||||
ValueTask<int> t = new ValueTask<int>(source);
|
||||
Assert.Same(source, t.AsTask());
|
||||
Assert.Same(t.AsTask(), t.AsTask());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFromValue_AsTaskNotIdempotent()
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
Assert.NotSame(Task.FromResult(42), t.AsTask());
|
||||
Assert.NotSame(t.AsTask(), t.AsTask());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateFromValue_Await()
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
Assert.Equal(42, await t);
|
||||
Assert.Equal(42, await t.ConfigureAwait(false));
|
||||
Assert.Equal(42, await t.ConfigureAwait(true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateFromTask_Await_Normal()
|
||||
{
|
||||
Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
|
||||
ValueTask<int> t = new ValueTask<int>(source);
|
||||
Assert.Equal(42, await t);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateFromTask_Await_ConfigureAwaitFalse()
|
||||
{
|
||||
Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
|
||||
ValueTask<int> t = new ValueTask<int>(source);
|
||||
Assert.Equal(42, await t.ConfigureAwait(false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateFromTask_Await_ConfigureAwaitTrue()
|
||||
{
|
||||
Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
|
||||
ValueTask<int> t = new ValueTask<int>(source);
|
||||
Assert.Equal(42, await t.ConfigureAwait(true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Awaiter_OnCompleted()
|
||||
{
|
||||
// Since ValueTask implements both OnCompleted and UnsafeOnCompleted,
|
||||
// OnCompleted typically won't be used by await, so we add an explicit test
|
||||
// for it here.
|
||||
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
t.GetAwaiter().OnCompleted(() => tcs.SetResult(true));
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task ConfiguredAwaiter_OnCompleted(bool continueOnCapturedContext)
|
||||
{
|
||||
// Since ValueTask implements both OnCompleted and UnsafeOnCompleted,
|
||||
// OnCompleted typically won't be used by await, so we add an explicit test
|
||||
// for it here.
|
||||
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => tcs.SetResult(true));
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Awaiter_ContinuesOnCapturedContext()
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var tsc = new TrackingSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(tsc);
|
||||
try
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
var mres = new ManualResetEventSlim();
|
||||
t.GetAwaiter().OnCompleted(() => mres.Set());
|
||||
Assert.True(mres.Wait(10000));
|
||||
Assert.Equal(1, tsc.Posts);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task ConfiguredAwaiter_ContinuesOnCapturedContext(bool continueOnCapturedContext)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var tsc = new TrackingSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(tsc);
|
||||
try
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
var mres = new ManualResetEventSlim();
|
||||
t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => mres.Set());
|
||||
Assert.True(mres.Wait(10000));
|
||||
Assert.Equal(continueOnCapturedContext ? 1 : 0, tsc.Posts);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHashCode_ContainsResult()
|
||||
{
|
||||
ValueTask<int> t = new ValueTask<int>(42);
|
||||
Assert.Equal(t.Result.GetHashCode(), t.GetHashCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHashCode_ContainsTask()
|
||||
{
|
||||
ValueTask<string> t = new ValueTask<string>(Task.FromResult("42"));
|
||||
Assert.Equal(t.AsTask().GetHashCode(), t.GetHashCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHashCode_ContainsNull()
|
||||
{
|
||||
ValueTask<string> t = new ValueTask<string>((string)null);
|
||||
Assert.Equal(0, t.GetHashCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OperatorEquals()
|
||||
{
|
||||
Assert.True(new ValueTask<int>(42) == new ValueTask<int>(42));
|
||||
Assert.False(new ValueTask<int>(42) == new ValueTask<int>(43));
|
||||
|
||||
Assert.True(new ValueTask<string>("42") == new ValueTask<string>("42"));
|
||||
Assert.True(new ValueTask<string>((string)null) == new ValueTask<string>((string)null));
|
||||
|
||||
Assert.False(new ValueTask<string>("42") == new ValueTask<string>((string)null));
|
||||
Assert.False(new ValueTask<string>((string)null) == new ValueTask<string>("42"));
|
||||
|
||||
Assert.False(new ValueTask<int>(42) == new ValueTask<int>(Task.FromResult(42)));
|
||||
Assert.False(new ValueTask<int>(Task.FromResult(42)) == new ValueTask<int>(42));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OperatorNotEquals()
|
||||
{
|
||||
Assert.False(new ValueTask<int>(42) != new ValueTask<int>(42));
|
||||
Assert.True(new ValueTask<int>(42) != new ValueTask<int>(43));
|
||||
|
||||
Assert.False(new ValueTask<string>("42") != new ValueTask<string>("42"));
|
||||
Assert.False(new ValueTask<string>((string)null) != new ValueTask<string>((string)null));
|
||||
|
||||
Assert.True(new ValueTask<string>("42") != new ValueTask<string>((string)null));
|
||||
Assert.True(new ValueTask<string>((string)null) != new ValueTask<string>("42"));
|
||||
|
||||
Assert.True(new ValueTask<int>(42) != new ValueTask<int>(Task.FromResult(42)));
|
||||
Assert.True(new ValueTask<int>(Task.FromResult(42)) != new ValueTask<int>(42));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equals_ValueTask()
|
||||
{
|
||||
Assert.True(new ValueTask<int>(42).Equals(new ValueTask<int>(42)));
|
||||
Assert.False(new ValueTask<int>(42).Equals(new ValueTask<int>(43)));
|
||||
|
||||
Assert.True(new ValueTask<string>("42").Equals(new ValueTask<string>("42")));
|
||||
Assert.True(new ValueTask<string>((string)null).Equals(new ValueTask<string>((string)null)));
|
||||
|
||||
Assert.False(new ValueTask<string>("42").Equals(new ValueTask<string>((string)null)));
|
||||
Assert.False(new ValueTask<string>((string)null).Equals(new ValueTask<string>("42")));
|
||||
|
||||
Assert.False(new ValueTask<int>(42).Equals(new ValueTask<int>(Task.FromResult(42))));
|
||||
Assert.False(new ValueTask<int>(Task.FromResult(42)).Equals(new ValueTask<int>(42)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equals_Object()
|
||||
{
|
||||
Assert.True(new ValueTask<int>(42).Equals((object)new ValueTask<int>(42)));
|
||||
Assert.False(new ValueTask<int>(42).Equals((object)new ValueTask<int>(43)));
|
||||
|
||||
Assert.True(new ValueTask<string>("42").Equals((object)new ValueTask<string>("42")));
|
||||
Assert.True(new ValueTask<string>((string)null).Equals((object)new ValueTask<string>((string)null)));
|
||||
|
||||
Assert.False(new ValueTask<string>("42").Equals((object)new ValueTask<string>((string)null)));
|
||||
Assert.False(new ValueTask<string>((string)null).Equals((object)new ValueTask<string>("42")));
|
||||
|
||||
Assert.False(new ValueTask<int>(42).Equals((object)new ValueTask<int>(Task.FromResult(42))));
|
||||
Assert.False(new ValueTask<int>(Task.FromResult(42)).Equals((object)new ValueTask<int>(42)));
|
||||
|
||||
Assert.False(new ValueTask<int>(42).Equals((object)null));
|
||||
Assert.False(new ValueTask<int>(42).Equals(new object()));
|
||||
Assert.False(new ValueTask<int>(42).Equals((object)42));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_Success()
|
||||
{
|
||||
Assert.Equal("Hello", new ValueTask<string>("Hello").ToString());
|
||||
Assert.Equal("Hello", new ValueTask<string>(Task.FromResult("Hello")).ToString());
|
||||
|
||||
Assert.Equal("42", new ValueTask<int>(42).ToString());
|
||||
Assert.Equal("42", new ValueTask<int>(Task.FromResult(42)).ToString());
|
||||
|
||||
Assert.Same(string.Empty, new ValueTask<string>(string.Empty).ToString());
|
||||
Assert.Same(string.Empty, new ValueTask<string>(Task.FromResult(string.Empty)).ToString());
|
||||
|
||||
Assert.Same(string.Empty, new ValueTask<string>(Task.FromException<string>(new InvalidOperationException())).ToString());
|
||||
Assert.Same(string.Empty, new ValueTask<string>(Task.FromException<string>(new OperationCanceledException())).ToString());
|
||||
|
||||
Assert.Same(string.Empty, new ValueTask<string>(Task.FromCanceled<string>(new CancellationToken(true))).ToString());
|
||||
|
||||
Assert.Equal("0", default(ValueTask<int>).ToString());
|
||||
Assert.Same(string.Empty, default(ValueTask<string>).ToString());
|
||||
Assert.Same(string.Empty, new ValueTask<string>((string)null).ToString());
|
||||
Assert.Same(string.Empty, new ValueTask<string>(Task.FromResult<string>(null)).ToString());
|
||||
|
||||
Assert.Same(string.Empty, new ValueTask<DateTime>(new TaskCompletionSource<DateTime>().Task).ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(ValueTask<>))]
|
||||
[InlineData(typeof(ValueTask<int>))]
|
||||
[InlineData(typeof(ValueTask<string>))]
|
||||
public void AsyncMethodBuilderAttribute_ValueTaskAttributed(Type valueTaskType)
|
||||
{
|
||||
CustomAttributeData cad = valueTaskType.GetTypeInfo().CustomAttributes.Single(attr => attr.AttributeType == typeof(AsyncMethodBuilderAttribute));
|
||||
Type builderTypeCtorArg = (Type)cad.ConstructorArguments[0].Value;
|
||||
Assert.Equal(typeof(AsyncValueTaskMethodBuilder<>), builderTypeCtorArg);
|
||||
|
||||
AsyncMethodBuilderAttribute amba = valueTaskType.GetTypeInfo().GetCustomAttribute<AsyncMethodBuilderAttribute>();
|
||||
Assert.Equal(builderTypeCtorArg, amba.BuilderType);
|
||||
}
|
||||
|
||||
private sealed class TrackingSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
internal int Posts { get; set; }
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
Posts++;
|
||||
base.Post(d, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user