|
|
@@ -0,0 +1,106 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
+
|
|
|
+namespace Avalonia.Utilities
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// A task-like operation that is guaranteed to finish continuations synchronously,
|
|
|
+ /// can be used for parametrized one-shot events
|
|
|
+ /// </summary>
|
|
|
+ public struct SynchronousCompletionAsyncResult<T> : INotifyCompletion
|
|
|
+ {
|
|
|
+ private readonly SynchronousCompletionAsyncResultSource<T> _source;
|
|
|
+ private readonly T _result;
|
|
|
+ private readonly bool _isValid;
|
|
|
+ internal SynchronousCompletionAsyncResult(SynchronousCompletionAsyncResultSource<T> source)
|
|
|
+ {
|
|
|
+ _source = source;
|
|
|
+ _result = default;
|
|
|
+ _isValid = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SynchronousCompletionAsyncResult(T result)
|
|
|
+ {
|
|
|
+ _result = result;
|
|
|
+ _source = null;
|
|
|
+ _isValid = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void ThrowNotInitialized() =>
|
|
|
+ throw new InvalidOperationException("This SynchronousCompletionAsyncResult was not initialized");
|
|
|
+
|
|
|
+ public bool IsCompleted
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ if (!_isValid)
|
|
|
+ ThrowNotInitialized();
|
|
|
+ return _source == null || _source.IsCompleted;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public T GetResult()
|
|
|
+ {
|
|
|
+ if (!_isValid)
|
|
|
+ ThrowNotInitialized();
|
|
|
+ return _source == null ? _result : _source.Result;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void OnCompleted(Action continuation)
|
|
|
+ {
|
|
|
+ if (!_isValid)
|
|
|
+ ThrowNotInitialized();
|
|
|
+ if (_source == null)
|
|
|
+ continuation();
|
|
|
+ else
|
|
|
+ _source.OnCompleted(continuation);
|
|
|
+ }
|
|
|
+
|
|
|
+ public SynchronousCompletionAsyncResult<T> GetAwaiter() => this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Source for incomplete SynchronousCompletionAsyncResult
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T"></typeparam>
|
|
|
+ public class SynchronousCompletionAsyncResultSource<T>
|
|
|
+ {
|
|
|
+ private T _result;
|
|
|
+ internal bool IsCompleted { get; private set; }
|
|
|
+ public SynchronousCompletionAsyncResult<T> AsyncResult => new SynchronousCompletionAsyncResult<T>(this);
|
|
|
+
|
|
|
+ internal T Result => IsCompleted ?
|
|
|
+ _result :
|
|
|
+ throw new InvalidOperationException("Asynchronous operation is not yet completed");
|
|
|
+
|
|
|
+ private List<Action> _continuations;
|
|
|
+
|
|
|
+ internal void OnCompleted(Action continuation)
|
|
|
+ {
|
|
|
+ if(_continuations==null)
|
|
|
+ _continuations = new List<Action>();
|
|
|
+ _continuations.Add(continuation);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetResult(T result)
|
|
|
+ {
|
|
|
+ if (IsCompleted)
|
|
|
+ throw new InvalidOperationException("Asynchronous operation is already completed");
|
|
|
+ _result = result;
|
|
|
+ IsCompleted = true;
|
|
|
+ if(_continuations!=null)
|
|
|
+ foreach (var c in _continuations)
|
|
|
+ c();
|
|
|
+ _continuations = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void TrySetResult(T result)
|
|
|
+ {
|
|
|
+ if(IsCompleted)
|
|
|
+ return;
|
|
|
+ SetResult(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|