11using System ;
22using System . Runtime . CompilerServices ;
33using System . Threading ;
4+ using UnityEngine ;
45using Object = UnityEngine . Object ;
56
67namespace UnityAsync
@@ -18,33 +19,54 @@ public interface IContinuation
1819 /// <typeparam name="T">The type of <see cref="UnityAsync.IAwaitInstruction"/> to encapsulate.</typeparam>
1920 public struct Continuation < T > : IContinuation , INotifyCompletion where T : IAwaitInstruction
2021 {
22+ static Exception exception ;
23+
2124 Object owner ;
2225 CancellationToken cancellationToken ;
2326
2427 /// <summary>
2528 /// Evaluate the encapsulated <see cref="UnityAsync.IAwaitInstruction"/>. If the instruction is finished, the
26- /// continuation delegate is invoked and the method returns <code>true</code>. If the owner is destroyed or a
27- /// cancellation was requested, the method will return true and will not invoke the continuation delegate.
28- /// Otherwise, the method will return false, meaning the <see cref="UnityAsync.IAwaitInstruction"/> is not yet
29- /// finished.
29+ /// continuation delegate is invoked and the method returns <code>true</code>. If the owner is destroyed, the
30+ /// method will return true without invoking the continuation delegate. If it was cancelled, an exception is
31+ /// is thrown when the continuation delegate is invoked. Otherwise, returns false (i.e. the instruction is not
32+ /// finished) .
3033 /// </summary>
3134 /// <returns>
32- /// <code>true</code> if the <see cref="UnityAsync.IAwaitInstruction"/> is finished or cancelled, otherwise
33- /// false.
35+ /// <code>true</code> if the <see cref="UnityAsync.IAwaitInstruction"/> is finished, its owner destroyed,
36+ /// or has been cancelled, otherwise <code> false</code> .
3437 /// </returns>
3538 public bool Evaluate ( )
3639 {
37- if ( ! owner || cancellationToken . IsCancellationRequested )
38- return true ;
39-
40- if ( instruction . IsCompleted ( ) )
40+ try
4141 {
42- continuation ( ) ;
42+ // if cancelled, throw exception
43+ cancellationToken . ThrowIfCancellationRequested ( ) ;
4344
44- return true ;
45+ // if owner is destroyed, behaves like a UnityEngine.Coroutine, ie:
46+ // "With this object's death, the thread of prophecy is severed. Restore a saved game to restore the
47+ // weave of fate, or persist in the doomed world you have created."
48+ if ( ! owner )
49+ return true ;
50+
51+ // if not completed, return false to put it back into a queue for next frame
52+ if ( ! instruction . IsCompleted ( ) )
53+ return false ;
4554 }
55+ catch ( Exception e )
56+ {
57+ // store exception in static field
58+ exception = e ;
59+
60+ // exception is rethrown in GetResult, at start of continuation
61+ continuation ( ) ;
4662
47- return false ;
63+ return true ;
64+ }
65+
66+ // if we get here, it completed without exceptions and we can call continuation and be done with it
67+ continuation ( ) ;
68+
69+ return true ;
4870 }
4971
5072 public FrameScheduler Scheduler { get ; private set ; }
@@ -57,6 +79,7 @@ public Continuation(T inst)
5779 instruction = inst ;
5880 continuation = null ;
5981 owner = AsyncManager . Instance ;
82+ exception = null ;
6083 Scheduler = FrameScheduler . Update ;
6184 }
6285
@@ -65,6 +88,7 @@ public Continuation(T inst, FrameScheduler scheduler)
6588 instruction = inst ;
6689 continuation = null ;
6790 owner = AsyncManager . Instance ;
91+ exception = null ;
6892 Scheduler = scheduler ;
6993 }
7094
@@ -73,6 +97,7 @@ public Continuation(T inst, CancellationToken cancellationToken, FrameScheduler
7397 instruction = inst ;
7498 continuation = null ;
7599 owner = AsyncManager . Instance ;
100+ exception = null ;
76101 this . cancellationToken = cancellationToken ;
77102 Scheduler = scheduler ;
78103 }
@@ -82,6 +107,7 @@ public Continuation(T inst, Object owner, FrameScheduler scheduler)
82107 instruction = inst ;
83108 continuation = null ;
84109 this . owner = owner ;
110+ exception = null ;
85111 Scheduler = scheduler ;
86112 }
87113
@@ -152,7 +178,16 @@ public Continuation<T> ConfigureAwait(CancellationToken cancellationToken)
152178 return this ;
153179 }
154180
155- public void GetResult ( ) { }
181+ public void GetResult ( )
182+ {
183+ if ( exception != null )
184+ {
185+ var e = exception ;
186+ exception = null ;
187+
188+ throw e ;
189+ }
190+ }
156191
157192 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
158193 public Continuation < T > GetAwaiter ( ) => this ;
0 commit comments