<commit_before>﻿using System;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Reactive.Bindings
{
    /// <summary>
    /// Represents AsyncReactiveCommand&lt;object&gt;
    /// </summary>
    public class AsyncReactiveCommand : AsyncReactiveCommand<object>
    {
        public AsyncReactiveCommand()
            : base()
        {

        }

        public AsyncReactiveCommand(IObservable<bool> canExecuteSource, bool initialValue = true)
            : base(canExecuteSource, initialValue)
        {
        }

        /// <summary>Push null to subscribers.</summary>
        public void Execute()
        {
            Execute(null);
        }
    }

    public class AsyncReactiveCommand<T> : ICommand, IDisposable
    {
        static readonly Task EmptyTask = Task.FromResult<object>(null);

        public event EventHandler CanExecuteChanged;

        readonly object gate = new object();

        readonly ReactiveProperty<bool> isExecuting;
        readonly IDisposable sourceSubscription;
        bool canExecute = true;
        bool isDisposed = false;
        Notifiers.ImmutableList<Func<T, Task>> asyncActions = Notifiers.ImmutableList<Func<T, Task>>.Empty;

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public AsyncReactiveCommand()
        {
            this.isExecuting = new ReactiveProperty<bool>(false);
            this.sourceSubscription = this.isExecuting.Subscribe(x =>
            {
                canExecute = !x;
                this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            });
        }

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// The source is shared between other AsyncReactiveCommand.
        /// </summary>
        public AsyncReactiveCommand(IObservable<bool> canExecuteSource, bool initialValue = true)
        {
            this.isExecuting = new ReactiveProperty<bool>(false);
            this.canExecute = initialValue;
            this.sourceSubscription = isExecuting.CombineLatest(canExecuteSource, (x, y) => !x && y)
                .DistinctUntilChanged()
                .Subscribe(x =>
                {
                    canExecute = x;
                    this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
                });
        }

        /// <summary>Return current canExecute status.</summary>
        public bool CanExecute()
        {
            return isDisposed ? false : canExecute;
        }

        /// <summary>Return current canExecute status. parameter is ignored.</summary>
        bool ICommand.CanExecute(object parameter)
        {
            return isDisposed ? false : canExecute;
        }

        /// <summary>Push parameter to subscribers, when executing CanExecuting is changed to false.</summary>
        public async void Execute(T parameter)
        {
            if (canExecute)
            {
                isExecuting.Value = true;
                var a = asyncActions.Data;
                if (a.Length == 1)
                {
                    try
                    {
                        var asyncState = a[0].Invoke(parameter) ?? EmptyTask;
                        await asyncState;
                    }
                    finally
                    {
                        isExecuting.Value = false;
                    }
                }
                else
                {
                    var xs = new Task[a.Length];
                    try
                    {
                        for (int i = 0; i < a.Length; i++)
                        {
                            xs[i] = a[i].Invoke(parameter) ?? EmptyTask;
                        }

                        await Task.WhenAll(xs);
                    }
                    finally
                    {
                        isExecuting.Value = false;
                    }
                }
            }
        }

        /// <summary>Push parameter to subscribers, when executing CanExecuting is changed to false.</summary>
        void ICommand.Execute(object parameter) => Execute((T)parameter);

        /// <summary>Subscribe execute.</summary>
        public IDisposable Subscribe(Func<T, Task> asyncAction)
        {
            lock (gate)
            {
                asyncActions = asyncActions.Add(asyncAction);
            }

            return new Subscription(this, asyncAction);
        }

        /// <summary>
        /// Stop all subscription and lock CanExecute is false.
        /// </summary>
        public void Dispose()
        {
            if (isDisposed) return;

            isDisposed = true;
            this.sourceSubscription.Dispose();
            if (canExecute)
            {
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        class Subscription : IDisposable
        {
            readonly AsyncReactiveCommand<T> parent;
            readonly Func<T, Task> asyncAction;

            public Subscription(AsyncReactiveCommand<T> parent, Func<T, Task> asyncAction)
            {
                this.parent = parent;
                this.asyncAction = asyncAction;
            }

            public void Dispose()
            {
                lock (parent.gate)
                {
                    parent.asyncActions = parent.asyncActions.Remove(asyncAction);
                }
            }
        }
    }

    public static class AsyncReactiveCommandExtensions
    {
        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public static AsyncReactiveCommand ToAsyncReactiveCommand(this IObservable<bool> canExecuteSource, bool initialValue = true) =>
            new AsyncReactiveCommand(canExecuteSource, initialValue);

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public static AsyncReactiveCommand<T> ToAsyncReactiveCommand<T>(this IObservable<bool> canExecuteSource, bool initialValue = true) =>
            new AsyncReactiveCommand<T>(canExecuteSource, initialValue);
    }
}<commit_msg>Three overloads for AsyncReactiveCommand<commit_after>﻿using System;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Reactive.Bindings
{
    /// <summary>
    /// Represents AsyncReactiveCommand&lt;object&gt;
    /// </summary>
    public class AsyncReactiveCommand : AsyncReactiveCommand<object>
    {
        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public AsyncReactiveCommand()
            : base()
        {

        }

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public AsyncReactiveCommand(IObservable<bool> canExecuteSource)
            : base(canExecuteSource)
        {
        }

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// The source is shared between other AsyncReactiveCommand.
        /// </summary>
        public AsyncReactiveCommand(IReactiveProperty<bool> sharedCanExecute)
            :base(sharedCanExecute)
        {
        }

        /// <summary>Push null to subscribers.</summary>
        public void Execute()
        {
            Execute(null);
        }
    }

    public class AsyncReactiveCommand<T> : ICommand, IDisposable
    {
        static readonly Task EmptyTask = Task.FromResult<object>(null);

        public event EventHandler CanExecuteChanged;

        readonly object gate = new object();
        readonly IReactiveProperty<bool> canExecute;
        readonly IDisposable sourceSubscription;
        bool isCanExecute;

        bool isDisposed = false;
        Notifiers.ImmutableList<Func<T, Task>> asyncActions = Notifiers.ImmutableList<Func<T, Task>>.Empty;

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public AsyncReactiveCommand()
        {
            this.canExecute = new ReactiveProperty<bool>(true);
            this.sourceSubscription = this.canExecute.Subscribe(x =>
            {
                this.isCanExecute = x;
                this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            });
        }

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public AsyncReactiveCommand(IObservable<bool> canExecuteSource)
        {
            this.canExecute = new ReactiveProperty<bool>(true);
            this.sourceSubscription = canExecute.CombineLatest(canExecuteSource, (x, y) => x && y)
                .DistinctUntilChanged()
                .Subscribe(x =>
                {
                    this.isCanExecute = x;
                    this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
                });
        }

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// The source is shared between other AsyncReactiveCommand.
        /// </summary>
        public AsyncReactiveCommand(IReactiveProperty<bool> sharedCanExecute)
        {
            this.canExecute = sharedCanExecute;
            this.sourceSubscription = this.canExecute.Subscribe(x =>
            {
                this.isCanExecute = x;
                this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            });
        }

        /// <summary>Return current canExecute status.</summary>
        public bool CanExecute()
        {
            return isDisposed ? false : isCanExecute;
        }

        /// <summary>Return current canExecute status. parameter is ignored.</summary>
        bool ICommand.CanExecute(object parameter)
        {
            return isDisposed ? false : isCanExecute;
        }

        /// <summary>Push parameter to subscribers, when executing CanExecuting is changed to false.</summary>
        public async void Execute(T parameter)
        {
            if (isCanExecute)
            {
                canExecute.Value = false;
                var a = asyncActions.Data;
                if (a.Length == 1)
                {
                    try
                    {
                        var asyncState = a[0].Invoke(parameter) ?? EmptyTask;
                        await asyncState;
                    }
                    finally
                    {
                        canExecute.Value = true;
                    }
                }
                else
                {
                    var xs = new Task[a.Length];
                    try
                    {
                        for (int i = 0; i < a.Length; i++)
                        {
                            xs[i] = a[i].Invoke(parameter) ?? EmptyTask;
                        }

                        await Task.WhenAll(xs);
                    }
                    finally
                    {
                        canExecute.Value = true;
                    }
                }
            }
        }

        /// <summary>Push parameter to subscribers, when executing CanExecuting is changed to false.</summary>
        void ICommand.Execute(object parameter) => Execute((T)parameter);

        /// <summary>Subscribe execute.</summary>
        public IDisposable Subscribe(Func<T, Task> asyncAction)
        {
            lock (gate)
            {
                asyncActions = asyncActions.Add(asyncAction);
            }

            return new Subscription(this, asyncAction);
        }

        /// <summary>
        /// Stop all subscription and lock CanExecute is false.
        /// </summary>
        public void Dispose()
        {
            if (isDisposed) return;

            isDisposed = true;
            this.sourceSubscription.Dispose();
            if (isCanExecute)
            {
                isCanExecute = false;
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        class Subscription : IDisposable
        {
            readonly AsyncReactiveCommand<T> parent;
            readonly Func<T, Task> asyncAction;

            public Subscription(AsyncReactiveCommand<T> parent, Func<T, Task> asyncAction)
            {
                this.parent = parent;
                this.asyncAction = asyncAction;
            }

            public void Dispose()
            {
                lock (parent.gate)
                {
                    parent.asyncActions = parent.asyncActions.Remove(asyncAction);
                }
            }
        }
    }

    public static class AsyncReactiveCommandExtensions
    {
        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public static AsyncReactiveCommand ToAsyncReactiveCommand(this IObservable<bool> canExecuteSource) =>
            new AsyncReactiveCommand(canExecuteSource);

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// </summary>
        public static AsyncReactiveCommand<T> ToAsyncReactiveCommand<T>(this IObservable<bool> canExecuteSource) =>
            new AsyncReactiveCommand<T>(canExecuteSource);


        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// The source is shared between other AsyncReactiveCommand.
        /// </summary>
        public static AsyncReactiveCommand ToAsyncReactiveCommand(this IReactiveProperty<bool> sharedCanExecute) =>
            new AsyncReactiveCommand(sharedCanExecute);

        /// <summary>
        /// CanExecute is automatically changed when executing to false and finished to true.
        /// The source is shared between other AsyncReactiveCommand.
        /// </summary>
        public static AsyncReactiveCommand<T> ToAsyncReactiveCommand<T>(this IReactiveProperty<bool> sharedCanExecute) =>
            new AsyncReactiveCommand<T>(sharedCanExecute);
    }
}
{'fraction_non_alphanumeric': 0.08701983081403411, 'fraction_numerical': 0.00041603106365275275, 'mean_word_length': 1.5419457173070144, 'pattern_counts': {'":': 0, '<': 116, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '260093', 'n_tokens_mistral': 3508, 'n_tokens_neox': 3326, 'n_words': 843}