File size: 7,919 Bytes
18a519f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | 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;
}
}
}
|