@@ -176,7 +176,17 @@ public Task AsTask()
176176 return
177177 obj == null ? Task . CompletedTask :
178178 obj as Task ??
179- GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource > ( obj ) ) ;
179+ GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource > ( obj ) , ValueTaskSourceOnCompletedFlags . None ) ;
180+ }
181+
182+ internal Task AsUnconfiguredTask ( )
183+ {
184+ object ? obj = _obj ;
185+ Debug . Assert ( obj == null || obj is Task || obj is IValueTaskSource ) ;
186+ return
187+ obj == null ? Task . CompletedTask :
188+ obj as Task ??
189+ GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource > ( obj ) , IValueTaskAsTask . _unconfigured ) ;
180190 }
181191
182192 /// <summary>Gets a <see cref="ValueTask"/> that may be used at any point in the future.</summary>
@@ -187,7 +197,7 @@ obj as Task ??
187197 /// The <see cref="IValueTaskSource"/> is passed in rather than reading and casting <see cref="_obj"/>
188198 /// so that the caller can pass in an object it's already validated.
189199 /// </remarks>
190- private Task GetTaskForValueTaskSource ( IValueTaskSource t )
200+ private Task GetTaskForValueTaskSource ( IValueTaskSource t , ValueTaskSourceOnCompletedFlags flags )
191201 {
192202 ValueTaskSourceStatus status = t . GetStatus ( _token ) ;
193203 if ( status != ValueTaskSourceStatus . Pending )
@@ -225,11 +235,11 @@ private Task GetTaskForValueTaskSource(IValueTaskSource t)
225235 }
226236 }
227237
228- return new ValueTaskSourceAsTask ( t , _token ) ;
238+ return new ValueTaskSourceAsTask ( t , _token , flags ) ;
229239 }
230240
231241 /// <summary>Type used to create a <see cref="Task"/> to represent a <see cref="IValueTaskSource"/>.</summary>
232- private sealed class ValueTaskSourceAsTask : Task
242+ private sealed class ValueTaskSourceAsTask : Task , IValueTaskAsTask
233243 {
234244 private static readonly Action < object ? > s_completionAction = static state =>
235245 {
@@ -283,11 +293,28 @@ state is ValueTaskSourceAsTask vsts ?
283293 /// <summary>The token to pass through to operations on <see cref="_source"/></summary>
284294 private readonly short _token ;
285295
286- internal ValueTaskSourceAsTask ( IValueTaskSource source , short token )
296+ private bool _configured ;
297+
298+ bool IValueTaskAsTask . IsConfigured => _configured ;
299+ void IValueTaskAsTask . Configure ( ValueTaskSourceOnCompletedFlags flags ) => Configure ( flags ) ;
300+
301+ private void Configure ( ValueTaskSourceOnCompletedFlags flags )
302+ {
303+ Debug . Assert ( ! _configured ) ;
304+
305+ _configured = true ;
306+ _source ! . OnCompleted ( s_completionAction , this , _token , flags ) ;
307+ }
308+
309+ internal ValueTaskSourceAsTask ( IValueTaskSource source , short token , ValueTaskSourceOnCompletedFlags flags )
287310 {
288311 _token = token ;
289312 _source = source ;
290- source . OnCompleted ( s_completionAction , this , token , ValueTaskSourceOnCompletedFlags . None ) ;
313+
314+ if ( flags != IValueTaskAsTask . _unconfigured )
315+ {
316+ Configure ( flags ) ;
317+ }
291318 }
292319 }
293320
@@ -585,7 +612,25 @@ public Task<TResult> AsTask()
585612 return t ;
586613 }
587614
588- return GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource < TResult > > ( obj ) ) ;
615+ return GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource < TResult > > ( obj ) , ValueTaskSourceOnCompletedFlags . None ) ;
616+ }
617+
618+ internal Task < TResult > AsUnconfiguredTask ( )
619+ {
620+ object ? obj = _obj ;
621+ Debug . Assert ( obj == null || obj is Task < TResult > || obj is IValueTaskSource < TResult > ) ;
622+
623+ if ( obj == null )
624+ {
625+ return Task . FromResult ( _result ! ) ;
626+ }
627+
628+ if ( obj is Task < TResult > t )
629+ {
630+ return t ;
631+ }
632+
633+ return GetTaskForValueTaskSource ( Unsafe . As < IValueTaskSource < TResult > > ( obj ) , IValueTaskAsTask . _unconfigured ) ;
589634 }
590635
591636 /// <summary>Gets a <see cref="ValueTask{TResult}"/> that may be used at any point in the future.</summary>
@@ -596,7 +641,7 @@ public Task<TResult> AsTask()
596641 /// The <see cref="IValueTaskSource{TResult}"/> is passed in rather than reading and casting <see cref="_obj"/>
597642 /// so that the caller can pass in an object it's already validated.
598643 /// </remarks>
599- private Task < TResult > GetTaskForValueTaskSource ( IValueTaskSource < TResult > t )
644+ private Task < TResult > GetTaskForValueTaskSource ( IValueTaskSource < TResult > t , ValueTaskSourceOnCompletedFlags flags )
600645 {
601646 ValueTaskSourceStatus status = t . GetStatus ( _token ) ;
602647 if ( status != ValueTaskSourceStatus . Pending )
@@ -633,11 +678,11 @@ private Task<TResult> GetTaskForValueTaskSource(IValueTaskSource<TResult> t)
633678 }
634679 }
635680
636- return new ValueTaskSourceAsTask ( t , _token ) ;
681+ return new ValueTaskSourceAsTask ( t , _token , flags ) ;
637682 }
638683
639684 /// <summary>Type used to create a <see cref="Task{TResult}"/> to represent a <see cref="IValueTaskSource{TResult}"/>.</summary>
640- private sealed class ValueTaskSourceAsTask : Task < TResult >
685+ private sealed class ValueTaskSourceAsTask : Task < TResult > , IValueTaskAsTask
641686 {
642687 private static readonly Action < object ? > s_completionAction = static state =>
643688 {
@@ -690,11 +735,28 @@ state is ValueTaskSourceAsTask vsts ?
690735 /// <summary>The token to pass through to operations on <see cref="_source"/></summary>
691736 private readonly short _token ;
692737
693- public ValueTaskSourceAsTask ( IValueTaskSource < TResult > source , short token )
738+ private bool _configured ;
739+
740+ bool IValueTaskAsTask . IsConfigured => _configured ;
741+ void IValueTaskAsTask . Configure ( ValueTaskSourceOnCompletedFlags flags ) => Configure ( flags ) ;
742+
743+ private void Configure ( ValueTaskSourceOnCompletedFlags flags )
744+ {
745+ Debug . Assert ( ! _configured ) ;
746+
747+ _configured = true ;
748+ _source ! . OnCompleted ( s_completionAction , this , _token , flags ) ;
749+ }
750+
751+ internal ValueTaskSourceAsTask ( IValueTaskSource < TResult > source , short token , ValueTaskSourceOnCompletedFlags flags )
694752 {
695- _source = source ;
696753 _token = token ;
697- source . OnCompleted ( s_completionAction , this , token , ValueTaskSourceOnCompletedFlags . None ) ;
754+ _source = source ;
755+
756+ if ( flags != IValueTaskAsTask . _unconfigured )
757+ {
758+ Configure ( flags ) ;
759+ }
698760 }
699761 }
700762
@@ -848,4 +910,12 @@ public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCaptu
848910 return string . Empty ;
849911 }
850912 }
913+
914+ internal interface IValueTaskAsTask
915+ {
916+ internal const ValueTaskSourceOnCompletedFlags _unconfigured = ( ValueTaskSourceOnCompletedFlags ) ( - 1 ) ;
917+
918+ bool IsConfigured { get ; }
919+ void Configure ( ValueTaskSourceOnCompletedFlags flags ) ;
920+ }
851921}
0 commit comments