196 lines
7.7 KiB
C#
196 lines
7.7 KiB
C#
|
using System;
|
||
|
using UnityEngine.Profiling;
|
||
|
|
||
|
namespace UnityEngine.InputSystem.Utilities
|
||
|
{
|
||
|
internal static class DelegateHelpers
|
||
|
{
|
||
|
// InvokeCallbacksSafe protects both against the callback getting removed while being called
|
||
|
// and against exceptions being thrown by the callback.
|
||
|
|
||
|
public static void InvokeCallbacksSafe(ref CallbackArray<Action> callbacks, string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return;
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
callbacks[i]();
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
}
|
||
|
|
||
|
public static void InvokeCallbacksSafe<TValue>(ref CallbackArray<Action<TValue>> callbacks, TValue argument, string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return;
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
callbacks[i](argument);
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
}
|
||
|
|
||
|
public static void InvokeCallbacksSafe<TValue1, TValue2>(ref CallbackArray<Action<TValue1, TValue2>> callbacks, TValue1 argument1, TValue2 argument2, string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return;
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
callbacks[i](argument1, argument2);
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
}
|
||
|
|
||
|
public static bool InvokeCallbacksSafe_AnyCallbackReturnsTrue<TValue1, TValue2>(ref CallbackArray<Func<TValue1, TValue2, bool>> callbacks,
|
||
|
TValue1 argument1, TValue2 argument2, string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return true;
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if (callbacks[i](argument1, argument2))
|
||
|
{
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invokes the given callbacks and also invokes any callback returned from the result of the first.
|
||
|
/// </summary>
|
||
|
/// <seealso cref="System.Action"/>
|
||
|
/// <remarks>
|
||
|
/// Allows an chaining up an additional, optional block of code to the original callback
|
||
|
/// and allow the external code make the decision about whether this code should be executed.
|
||
|
/// </remarks>
|
||
|
public static void InvokeCallbacksSafe_AndInvokeReturnedActions<TValue>(
|
||
|
ref CallbackArray<Func<TValue, Action>> callbacks, TValue argument,
|
||
|
string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return;
|
||
|
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
callbacks[i](argument)?.Invoke();
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invokes the given callbacks and returns true if any of them returned a non-null result.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Returns false if every callback invocation returned null.
|
||
|
/// </remarks>
|
||
|
public static bool InvokeCallbacksSafe_AnyCallbackReturnsObject<TValue, TReturn>(
|
||
|
ref CallbackArray<Func<TValue, TReturn>> callbacks, TValue argument,
|
||
|
string callbackName, object context = null)
|
||
|
{
|
||
|
if (callbacks.length == 0)
|
||
|
return false;
|
||
|
|
||
|
Profiler.BeginSample(callbackName);
|
||
|
callbacks.LockForChanges();
|
||
|
for (var i = 0; i < callbacks.length; ++i)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
var ret = callbacks[i](argument);
|
||
|
if (ret != null)
|
||
|
{
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Debug.LogException(exception);
|
||
|
if (context != null)
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks of '{context}'");
|
||
|
else
|
||
|
Debug.LogError($"{exception.GetType().Name} while executing '{callbackName}' callbacks");
|
||
|
}
|
||
|
}
|
||
|
callbacks.UnlockForChanges();
|
||
|
Profiler.EndSample();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|