using System; using MessagePipe.Internal; using System.Threading; using Cysharp.Threading.Tasks; namespace MessagePipe { public static partial class SubscriberExtensions { public static UniTask FirstAsync(this ISubscriber subscriber, CancellationToken cancellationToken, params MessageHandlerFilter[] filters) { return new UniTask(new FirstAsyncMessageHandler(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this ISubscriber subscriber, CancellationToken cancellationToken, Func predicate, params MessageHandlerFilter[] filters) { var predicateFilter = new PredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return new UniTask(new FirstAsyncMessageHandler(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IBufferedSubscriber subscriber, CancellationToken cancellationToken, params MessageHandlerFilter[] filters) { return new UniTask(new FirstAsyncBufferedMessageHandler(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IBufferedSubscriber subscriber, CancellationToken cancellationToken, Func predicate, params MessageHandlerFilter[] filters) { var predicateFilter = new PredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return new UniTask(new FirstAsyncBufferedMessageHandler(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IAsyncSubscriber subscriber, CancellationToken cancellationToken, params AsyncMessageHandlerFilter[] filters) { return new UniTask(new FirstAsyncAsyncMessageHandler(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IAsyncSubscriber subscriber, CancellationToken cancellationToken, Func predicate, params AsyncMessageHandlerFilter[] filters) { var predicateFilter = new AsyncPredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return new UniTask(new FirstAsyncAsyncMessageHandler(subscriber, cancellationToken, filters), 0); } public static async UniTask FirstAsync(this IBufferedAsyncSubscriber subscriber, CancellationToken cancellationToken, params AsyncMessageHandlerFilter[] filters) { return await new UniTask(await FirstAsyncAsyncBufferedMessageHandler.CreateAsync(subscriber, cancellationToken, filters), 0); } public static async UniTask FirstAsync(this IBufferedAsyncSubscriber subscriber, CancellationToken cancellationToken, Func predicate, params AsyncMessageHandlerFilter[] filters) { var predicateFilter = new AsyncPredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return await new UniTask(await FirstAsyncAsyncBufferedMessageHandler.CreateAsync(subscriber, cancellationToken, filters), 0); } public static UniTask FirstAsync(this ISubscriber subscriber, TKey key, CancellationToken cancellationToken, params MessageHandlerFilter[] filters) { return new UniTask(new FirstAsyncMessageHandler(subscriber, key, cancellationToken, filters), 0); } public static UniTask FirstAsync(this ISubscriber subscriber, TKey key, CancellationToken cancellationToken, Func predicate, params MessageHandlerFilter[] filters) { var predicateFilter = new PredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return new UniTask(new FirstAsyncMessageHandler(subscriber, key, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IAsyncSubscriber subscriber, TKey key, CancellationToken cancellationToken, params AsyncMessageHandlerFilter[] filters) { return new UniTask(new FirstAsyncAsyncMessageHandler(subscriber, key, cancellationToken, filters), 0); } public static UniTask FirstAsync(this IAsyncSubscriber subscriber, TKey key, CancellationToken cancellationToken, Func predicate, params AsyncMessageHandlerFilter[] filters) { var predicateFilter = new AsyncPredicateFilter(predicate); filters = (filters.Length == 0) ? new[] { predicateFilter } : ArrayUtil.ImmutableAdd(filters, predicateFilter); return new UniTask(new FirstAsyncAsyncMessageHandler(subscriber, key, cancellationToken, filters), 0); } } internal sealed class FirstAsyncMessageHandler : IMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public FirstAsyncMessageHandler(ISubscriber subscriber, TKey key, CancellationToken cancellationToken, MessageHandlerFilter[] filters) { if (cancellationToken.IsCancellationRequested) { this.core.TrySetException(new OperationCanceledException(cancellationToken)); return; } try { this.subscription = subscriber.Subscribe(key, this, filters); } catch (Exception ex) { this.core.TrySetException(ex); return; } if (handleCalled != 0) { this.subscription?.Dispose(); return; } if (cancellationToken.CanBeCanceled) { this.cancellationToken = cancellationToken; this.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, this, false); } } static void Cancel(object state) { var self = (FirstAsyncMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public void Handle(TMessage message) { if (Interlocked.Increment(ref handleCalled) == 1) { try { core.TrySetResult(message); } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } internal sealed class FirstAsyncMessageHandler : IMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public FirstAsyncMessageHandler(ISubscriber subscriber, CancellationToken cancellationToken, MessageHandlerFilter[] filters) { if (cancellationToken.IsCancellationRequested) { this.core.TrySetException(new OperationCanceledException(cancellationToken)); return; } try { this.subscription = subscriber.Subscribe(this, filters); } catch (Exception ex) { this.core.TrySetException(ex); return; } if (handleCalled != 0) { this.subscription?.Dispose(); return; } if (cancellationToken.CanBeCanceled) { this.cancellationToken = cancellationToken; this.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, this, false); } } static void Cancel(object state) { var self = (FirstAsyncMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public void Handle(TMessage message) { if (Interlocked.Increment(ref handleCalled) == 1) { try { core.TrySetResult(message); } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } internal sealed class FirstAsyncBufferedMessageHandler : IMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public FirstAsyncBufferedMessageHandler(IBufferedSubscriber subscriber, CancellationToken cancellationToken, MessageHandlerFilter[] filters) { if (cancellationToken.IsCancellationRequested) { this.core.TrySetException(new OperationCanceledException(cancellationToken)); return; } try { this.subscription = subscriber.Subscribe(this, filters); } catch (Exception ex) { this.core.TrySetException(ex); return; } if (handleCalled != 0) { this.subscription?.Dispose(); return; } if (cancellationToken.CanBeCanceled) { this.cancellationToken = cancellationToken; this.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, this, false); } } static void Cancel(object state) { var self = (FirstAsyncBufferedMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public void Handle(TMessage message) { if (Interlocked.Increment(ref handleCalled) == 1) { try { core.TrySetResult(message); } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } internal sealed class FirstAsyncAsyncMessageHandler : IAsyncMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public FirstAsyncAsyncMessageHandler(IAsyncSubscriber subscriber, TKey key, CancellationToken cancellationToken, AsyncMessageHandlerFilter[] filters) { if (cancellationToken.IsCancellationRequested) { this.core.TrySetException(new OperationCanceledException(cancellationToken)); return; } try { this.subscription = subscriber.Subscribe(key, this, filters); } catch (Exception ex) { this.core.TrySetException(ex); return; } if (handleCalled != 0) { this.subscription?.Dispose(); return; } if (cancellationToken.CanBeCanceled) { this.cancellationToken = cancellationToken; this.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, this, false); } } static void Cancel(object state) { var self = (FirstAsyncAsyncMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public UniTask HandleAsync(TMessage message, CancellationToken cancellationToken) { if (Interlocked.Increment(ref handleCalled) == 1) { try { if (cancellationToken.IsCancellationRequested) { core.TrySetException(new OperationCanceledException(cancellationToken)); } else { core.TrySetResult(message); } } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } return default; } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } internal sealed class FirstAsyncAsyncMessageHandler : IAsyncMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public FirstAsyncAsyncMessageHandler(IAsyncSubscriber subscriber, CancellationToken cancellationToken, AsyncMessageHandlerFilter[] filters) { if (cancellationToken.IsCancellationRequested) { this.core.TrySetException(new OperationCanceledException(cancellationToken)); return; } try { this.subscription = subscriber.Subscribe(this, filters); } catch (Exception ex) { this.core.TrySetException(ex); return; } if (handleCalled != 0) { this.subscription?.Dispose(); return; } if (cancellationToken.CanBeCanceled) { this.cancellationToken = cancellationToken; this.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, this, false); } } static void Cancel(object state) { var self = (FirstAsyncAsyncMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public UniTask HandleAsync(TMessage message, CancellationToken cancellationToken) { if (Interlocked.Increment(ref handleCalled) == 1) { try { if (cancellationToken.IsCancellationRequested) { core.TrySetException(new OperationCanceledException(cancellationToken)); } else { core.TrySetResult(message); } } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } return default; } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } internal sealed class FirstAsyncAsyncBufferedMessageHandler : IAsyncMessageHandler, IUniTaskSource { int handleCalled = 0; IDisposable subscription; CancellationToken cancellationToken; CancellationTokenRegistration cancellationTokenRegistration; UniTaskCompletionSourceCore core; static readonly Action cancelCallback = Cancel; public static async UniTask> CreateAsync(IBufferedAsyncSubscriber subscriber, CancellationToken cancellationToken, AsyncMessageHandlerFilter[] filters) { var self = new FirstAsyncAsyncBufferedMessageHandler(); if (cancellationToken.IsCancellationRequested) { self.core.TrySetException(new OperationCanceledException(cancellationToken)); return self; } try { self.subscription = await subscriber.SubscribeAsync(self, filters).ConfigureAwait(false); } catch (Exception ex) { self.core.TrySetException(ex); return self; } if (self.handleCalled != 0) { self.subscription?.Dispose(); return self; } if (cancellationToken.CanBeCanceled) { self.cancellationToken = cancellationToken; self.cancellationTokenRegistration = cancellationToken.Register(cancelCallback, self, false); } return self; } static void Cancel(object state) { var self = (FirstAsyncAsyncBufferedMessageHandler)state; self.subscription?.Dispose(); self.core.TrySetException(new OperationCanceledException(self.cancellationToken)); } public UniTask HandleAsync(TMessage message, CancellationToken cancellationToken) { if (Interlocked.Increment(ref handleCalled) == 1) { try { if (cancellationToken.IsCancellationRequested) { core.TrySetException(new OperationCanceledException(cancellationToken)); } else { core.TrySetResult(message); } } finally { subscription?.Dispose(); cancellationTokenRegistration.Dispose(); } } return default; } void IUniTaskSource.GetResult(short token) => GetResult(token); public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus(); public /*replaced*/ UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public TMessage GetResult(short token) { return core.GetResult(token); } } }