using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Chernobyl.Collections.Generic;
using Chernobyl.Destruction;
using Enumerable = System.Linq.Enumerable;
namespace Chernobyl
{
///
/// Encapsulates a method that has four parameters and does not return a value.
///
public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
///
/// Utility and extension methods for the action delegates.
///
public static class ActionExt
{
///
/// Returns . This method makes writing in a fluent style a little easier.
///
public static Action This(Action action) => action;
///
/// Returns . This method makes writing in a fluent style a little easier.
///
public static Action This(Action action) => action;
///
/// Returns . This method makes writing in a fluent style a little easier.
///
public static Action This(Action action) => action;
///
/// Joins together multiple actions into a single action.
///
public static Action Join(IEnumerable> actions) =>
arg1 => actions.For(a => a(arg1));
///
/// Joins together multiple actions into a single action.
///
public static Action Join(params Action[] actions) => Join(actions.AsEnumerable());
///
/// Invokes all of the methods in the list.
///
public static void Invoke(this IEnumerable actions) => actions.For(a => a());
///
/// Invokes all of the methods in the list with the provided argument.
///
public static void Invoke(this IEnumerable> actions, T1 arg1) => actions.For(a => a(arg1));
///
/// Returns a method that projects the argument given to it using
/// before passing the projection onto .
///
public static Action Select(this Action action, Func selector) =>
arg1 => action(selector(arg1));
///
/// Returns a method that invokes with its first argument replaced
/// by the result of .
///
public static Action SelectArg1(this Action action, Func selector) =>
(arg1, arg2) => action(selector(arg1), arg2);
///
/// Returns a method that invokes with its second argument replaced
/// by the result of .
///
public static Action SelectArg2(this Action action, Func selector) =>
(arg1, arg2) => action(arg1, selector(arg2));
///
/// Returns a method that, when invoked, invokes but only if
/// returns true.
///
public static Action Where(this Action action, Func predicate) =>
v =>
{
if (predicate(v)) action(v);
};
///
/// Returns a method that, when invoked, invokes but only if
/// returns true.
///
public static Action Where(this Action action, Func predicate)
{
return (arg1, arg2) =>
{
if (predicate(arg1, arg2)) action(arg1, arg2);
};
}
///
/// Returns a method that, when invoked, invokes but only if
/// returns true.
///
public static Action WhereArg2(this Action action, Func predicate)
{
return (arg1, arg2) =>
{
if (predicate(arg2)) action(arg1, arg2);
};
}
///
/// Returns a method that, when invoked, invokes but only if
/// returns true.
///
public static Action Where(this Action action, Func predicate)
{
return (arg1, arg2, arg3) =>
{
if (predicate(arg1, arg2, arg3)) action(arg1, arg2, arg3);
};
}
///
/// Returns a method that uses the provided value as the second argument to the provided method.
///
public static Action BindArg1(this Action action, Arg arg1) =>
arg2 => action(arg1.Func(), arg2);
///
/// Returns a method that uses the provided value as the second argument to the provided method.
///
public static Action BindArg2(this Action action, Arg arg2) =>
arg1 => action(arg1, arg2.Func());
///
/// Returns a method two parameter that invokes with the second
/// argument but not the first.
///
public static Action PrependArg(this Action action) => (arg1, arg2) => action(arg2);
///
/// Returns a no-operation .
///
public static Action None() => arg1 => {};
///
/// Returns a no-operation .
///
public static Action None() => (arg1, arg2) => {};
}
///
/// An instance that can be converted to an that, when invoked,
/// invokes a set of and allows removal from that list when
/// dictated by an . This type is thread safe.
///
public class CompositeAction : CompositeAction
{
///
/// Adds an to be updated which can be removed by calling
/// on the returned instance. This method and the returned
/// is thread safe.
///
public IDisposable Register(Action action) => Register(arg1 => action());
///
/// Converts this instance to an so that can be invoked like one.
///
public static implicit operator Action(CompositeAction a) => a.Invoke;
///
/// Invokes all of the instances. This call is thread safe.
///
public void Invoke() => Invoke(0);
}
///
/// An instance that can be converted to an that, when invoked,
/// invokes a set of and allows removal from that list when
/// dictated by an . This type is thread safe.
///
public class CompositeAction
{
///
/// Adds an to be updated which can be removed by calling
/// on the returned instance. This method and the returned
/// is thread safe.
///
public IDisposable Register(Action action)
{
_actions.TryAdd(action, action);
return ActionExt.This(() => _actions.TryRemove(action, out _)).AsDisposable();
}
///
/// Converts this instance to an so that can be invoked like one.
///
public static implicit operator Action(CompositeAction action) => action.Action;
///
/// Invokes all of the instances. This call is thread safe.
///
public void Invoke(T1 arg1) => _actions.For(a => a.Value(arg1));
///
/// Performs the same function as . This property makes fluent
/// programming easier.
///
public Action Action => Invoke;
// Using ConcurrentDictionary because it is the only concurrent collection that allows for
// removal by value (i.e. TryRemove).
readonly ConcurrentDictionary, Action> _actions =
new ConcurrentDictionary, Action>();
}
///
/// An functor that holds onto the last value it was given. This type
/// can be implicitly converted to an .
///
/// This type is NOT thread safe.
public class LastValue
{
///
/// The last value given to the this .
///
public T Value { get; private set; }
///
/// Converts this functor to an .
///
public static implicit operator Action(LastValue lv) => lv.Accept;
///
/// The that accepts the value.
///
public void Accept(T value) => Value = value;
}
///
/// An functor that toggles between two states. This type
/// can be implicitly converted to an .
///
/// This type is NOT thread safe.
public class Toggle
{
///
/// Constructs the toggle with an initial state of false.
///
public Toggle() : this(false, null) { }
/// The initial state of this instance.
/// Method to invoke when value is toggled.
public Toggle(bool state, Action onStateChange = null)
{
State = state;
_onStateChange = onStateChange ?? ActionExt.None();
}
///
/// The current state of this instance.
///
public bool State { get; private set; }
///
/// Converts this functor to an .
///
public static implicit operator Action(Toggle t) => t.Invoke;
///
/// The that accepts the value.
///
public void Invoke()
{
State = !State;
_onStateChange(State);
}
readonly Action _onStateChange;
}
///
/// An functor that can be disposed of.
///
public class DisposableAction : IDisposable
{
/// The action to be invoked.
/// The result of disposing the action.
public DisposableAction(Action action, Action onDispose)
{
Action = action;
_onDispose = onDispose;
}
///
/// Projects this functor into another form.
///
/// The method that projects the action.
/// The new form of the functor.
public DisposableAction Select(Func, Action> selector) =>
new DisposableAction(selector(Action), _onDispose);
///
/// Converts this instance into its .
///
public static implicit operator Action(DisposableAction da) => da.Action;
///
/// The of this functor.
///
public Action Action { get; }
///
public void Dispose() => _onDispose();
readonly Action _onDispose;
}
}