b5ecd7924ccdb04dbac84610ec68d142b20bb5b1
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Runtime / CompilerServices / AsyncValueTaskMethodBuilder.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Runtime.InteropServices;
6 using System.Security;
7 using System.Threading.Tasks;
8
9 namespace System.Runtime.CompilerServices
10 {
11     /// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
12     /// <typeparam name="TResult">The type of the result.</typeparam>
13     [StructLayout(LayoutKind.Auto)]
14     public struct AsyncValueTaskMethodBuilder<TResult>
15     {
16         /// <summary>The <see cref="AsyncTaskMethodBuilder{TResult}"/> to which most operations are delegated.</summary>
17         private AsyncTaskMethodBuilder<TResult> _methodBuilder; // mutable struct; do not make it readonly
18         /// <summary>The result for this builder, if it's completed before any awaits occur.</summary>
19         private TResult _result;
20         /// <summary>true if <see cref="_result"/> contains the synchronous result for the async method; otherwise, false.</summary>
21         private bool _haveResult;
22         /// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
23         private bool _useBuilder;
24
25         /// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder{TResult}"/> struct.</summary>
26         /// <returns>The initialized instance.</returns>
27         public static AsyncValueTaskMethodBuilder<TResult> Create() =>
28 #if CORERT
29             // corert's AsyncTaskMethodBuilder<TResult>.Create() currently does additional debugger-related
30             // work, so we need to delegate to it.
31             new AsyncValueTaskMethodBuilder<TResult>() { _methodBuilder = AsyncTaskMethodBuilder<TResult>.Create() };
32 #else
33             // _methodBuilder should be initialized to AsyncTaskMethodBuilder<TResult>.Create(), but on coreclr
34             // that Create() is a nop, so we can just return the default here.
35             default(AsyncValueTaskMethodBuilder<TResult>);
36 #endif
37
38         /// <summary>Begins running the builder with the associated state machine.</summary>
39         /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
40         /// <param name="stateMachine">The state machine instance, passed by reference.</param>
41         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
42             _methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
43
44         /// <summary>Associates the builder with the specified state machine.</summary>
45         /// <param name="stateMachine">The state machine instance to associate with the builder.</param>
46         public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
47
48         /// <summary>Marks the task as successfully completed.</summary>
49         /// <param name="result">The result to use to complete the task.</param>
50         public void SetResult(TResult result)
51         {
52             if (_useBuilder)
53             {
54                 _methodBuilder.SetResult(result);
55             }
56             else
57             {
58                 _result = result;
59                 _haveResult = true;
60             }
61         }
62
63         /// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
64         /// <param name="exception">The exception to bind to the task.</param>
65         public void SetException(Exception exception) => _methodBuilder.SetException(exception);
66
67         /// <summary>Gets the task for this builder.</summary>
68         public ValueTask<TResult> Task
69         {
70             get
71             {
72                 if (_haveResult)
73                 {
74                     return new ValueTask<TResult>(_result);
75                 }
76                 else
77                 {
78                     _useBuilder = true;
79                     return new ValueTask<TResult>(_methodBuilder.Task);
80                 }
81             }
82         }
83
84         /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
85         /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
86         /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
87         /// <param name="awaiter">the awaiter</param>
88         /// <param name="stateMachine">The state machine.</param>
89         public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
90             where TAwaiter : INotifyCompletion
91             where TStateMachine : IAsyncStateMachine
92         {
93             _useBuilder = true;
94             _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
95         }
96
97         /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
98         /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
99         /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
100         /// <param name="awaiter">the awaiter</param>
101         /// <param name="stateMachine">The state machine.</param>
102         [SecuritySafeCritical]
103         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
104             where TAwaiter : ICriticalNotifyCompletion 
105             where TStateMachine : IAsyncStateMachine
106         {
107             _useBuilder = true;
108             _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
109         }
110     }
111 }