123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
- using System;
- using System.Threading;
- namespace Cysharp.Threading.Tasks
- {
- public class AsyncLazy
- {
- static Action<object> continuation = SetCompletionSource;
- Func<UniTask> taskFactory;
- UniTaskCompletionSource completionSource;
- UniTask.Awaiter awaiter;
- object syncLock;
- bool initialized;
- public AsyncLazy(Func<UniTask> taskFactory)
- {
- this.taskFactory = taskFactory;
- this.completionSource = new UniTaskCompletionSource();
- this.syncLock = new object();
- this.initialized = false;
- }
- internal AsyncLazy(UniTask task)
- {
- this.taskFactory = null;
- this.completionSource = new UniTaskCompletionSource();
- this.syncLock = null;
- this.initialized = true;
- var awaiter = task.GetAwaiter();
- if (awaiter.IsCompleted)
- {
- SetCompletionSource(awaiter);
- }
- else
- {
- this.awaiter = awaiter;
- awaiter.SourceOnCompleted(continuation, this);
- }
- }
- public UniTask Task
- {
- get
- {
- EnsureInitialized();
- return completionSource.Task;
- }
- }
- public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
- void EnsureInitialized()
- {
- if (Volatile.Read(ref initialized))
- {
- return;
- }
- EnsureInitializedCore();
- }
- void EnsureInitializedCore()
- {
- lock (syncLock)
- {
- if (!Volatile.Read(ref initialized))
- {
- var f = Interlocked.Exchange(ref taskFactory, null);
- if (f != null)
- {
- var task = f();
- var awaiter = task.GetAwaiter();
- if (awaiter.IsCompleted)
- {
- SetCompletionSource(awaiter);
- }
- else
- {
- this.awaiter = awaiter;
- awaiter.SourceOnCompleted(continuation, this);
- }
- Volatile.Write(ref initialized, true);
- }
- }
- }
- }
- void SetCompletionSource(in UniTask.Awaiter awaiter)
- {
- try
- {
- awaiter.GetResult();
- completionSource.TrySetResult();
- }
- catch (Exception ex)
- {
- completionSource.TrySetException(ex);
- }
- }
- static void SetCompletionSource(object state)
- {
- var self = (AsyncLazy)state;
- try
- {
- self.awaiter.GetResult();
- self.completionSource.TrySetResult();
- }
- catch (Exception ex)
- {
- self.completionSource.TrySetException(ex);
- }
- finally
- {
- self.awaiter = default;
- }
- }
- }
- public class AsyncLazy<T>
- {
- static Action<object> continuation = SetCompletionSource;
- Func<UniTask<T>> taskFactory;
- UniTaskCompletionSource<T> completionSource;
- UniTask<T>.Awaiter awaiter;
- object syncLock;
- bool initialized;
- public AsyncLazy(Func<UniTask<T>> taskFactory)
- {
- this.taskFactory = taskFactory;
- this.completionSource = new UniTaskCompletionSource<T>();
- this.syncLock = new object();
- this.initialized = false;
- }
- internal AsyncLazy(UniTask<T> task)
- {
- this.taskFactory = null;
- this.completionSource = new UniTaskCompletionSource<T>();
- this.syncLock = null;
- this.initialized = true;
- var awaiter = task.GetAwaiter();
- if (awaiter.IsCompleted)
- {
- SetCompletionSource(awaiter);
- }
- else
- {
- this.awaiter = awaiter;
- awaiter.SourceOnCompleted(continuation, this);
- }
- }
- public UniTask<T> Task
- {
- get
- {
- EnsureInitialized();
- return completionSource.Task;
- }
- }
- public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
- void EnsureInitialized()
- {
- if (Volatile.Read(ref initialized))
- {
- return;
- }
- EnsureInitializedCore();
- }
- void EnsureInitializedCore()
- {
- lock (syncLock)
- {
- if (!Volatile.Read(ref initialized))
- {
- var f = Interlocked.Exchange(ref taskFactory, null);
- if (f != null)
- {
- var task = f();
- var awaiter = task.GetAwaiter();
- if (awaiter.IsCompleted)
- {
- SetCompletionSource(awaiter);
- }
- else
- {
- this.awaiter = awaiter;
- awaiter.SourceOnCompleted(continuation, this);
- }
- Volatile.Write(ref initialized, true);
- }
- }
- }
- }
- void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
- {
- try
- {
- var result = awaiter.GetResult();
- completionSource.TrySetResult(result);
- }
- catch (Exception ex)
- {
- completionSource.TrySetException(ex);
- }
- }
- static void SetCompletionSource(object state)
- {
- var self = (AsyncLazy<T>)state;
- try
- {
- var result = self.awaiter.GetResult();
- self.completionSource.TrySetResult(result);
- }
- catch (Exception ex)
- {
- self.completionSource.TrySetException(ex);
- }
- finally
- {
- self.awaiter = default;
- }
- }
- }
- }
|