using System; using System.Runtime.CompilerServices; using Windows.UI.Core; using Windows.UI.Xaml; namespace OwlCore.WinUI.Threading { /// /// Builds a new . /// public class UiTaskMethodBuilder { private readonly CoreDispatcher _dispatcher; /// /// Creates a new instance of . /// /// public UiTaskMethodBuilder(CoreDispatcher dispatcher) { _dispatcher = dispatcher; } /// /// Starts the async machine. /// public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { if (!_dispatcher.HasThreadAccess) { var action = new Action(stateMachine.MoveNext); _ = _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); } else { stateMachine.MoveNext(); } } /// /// Creates a singleton of . /// /// public static UiTaskMethodBuilder Create() { return new UiTaskMethodBuilder(Window.Current.Dispatcher); } /// /// This one is pretty obscure, I’m not even sure when it’s supposed to be called. We’re not going to need it so we’ll leave it empty. /// public void SetStateMachine(IAsyncStateMachine stateMachine) { } /// /// Called at the end of the async method, to set the result. We can simply map to the TaskCompletionSource. /// public void SetResult() { Task.Promise.SetResult(new object()); } /// /// Called at the end of the async method, to set an exception. We can simply map to the TaskCompletionSource. /// /// public void SetException(Exception exception) { Task.Promise.SetException(exception); } /// /// Exposes the instance of our custom UI task that will be returned by the async method /// public UiTask Task { get; } = new UiTask(); /// /// Called to set the completion state. /// public void AwaitOnCompleted( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { awaiter.OnCompleted(ResumeAfterAwait(stateMachine)); } /// /// Called to set the completion state, if the awaiter implements ICriticalNotifyCompletion. /// public void AwaitUnsafeOnCompleted( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { awaiter.UnsafeOnCompleted(ResumeAfterAwait(stateMachine)); } private Action ResumeAfterAwait(TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { return () => { if (!_dispatcher.HasThreadAccess) { var action = new Action(stateMachine.MoveNext); _ = _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); } else { stateMachine.MoveNext(); } }; } } }