diff options
-rw-r--r-- | lib/Plugins.Runtime/src/LivePlugin.cs | 40 | ||||
-rw-r--r-- | lib/Utils/src/Resources/ManagedLibrary.cs | 80 |
2 files changed, 89 insertions, 31 deletions
diff --git a/lib/Plugins.Runtime/src/LivePlugin.cs b/lib/Plugins.Runtime/src/LivePlugin.cs index 3ed2ad6..26276dd 100644 --- a/lib/Plugins.Runtime/src/LivePlugin.cs +++ b/lib/Plugins.Runtime/src/LivePlugin.cs @@ -26,6 +26,7 @@ using System; using System.Linq; using System.Reflection; +using VNLib.Utils.Resources; using VNLib.Plugins.Attributes; namespace VNLib.Plugins.Runtime @@ -76,18 +77,14 @@ namespace VNLib.Plugins.Runtime Plugin = plugin; OriginAsm = originAsm; PluginType = plugin.GetType(); - GetConsoleHandler(); + PluginConsoleHandler = GetConsoleHandler(plugin); } - private void GetConsoleHandler() + private static ConsoleEventHandlerSignature? GetConsoleHandler(IPlugin plugin) { - //Get the console handler method from the plugin instance - MethodInfo? handler = (from m in PluginType.GetMethods() - where m.GetCustomAttribute<ConsoleEventHandlerAttribute>() != null - select m) - .FirstOrDefault(); //Get a delegate handler for the plugin - PluginConsoleHandler = handler?.CreateDelegate<ConsoleEventHandlerSignature>(Plugin); + return ManagedLibrary.GetMethodsWithAttribute<ConsoleEventHandlerAttribute, ConsoleEventHandlerSignature>(plugin) + .FirstOrDefault(); } /// <summary> @@ -97,18 +94,9 @@ namespace VNLib.Plugins.Runtime /// <param name="configData">The host configuration DOM</param> internal void InitConfig(ReadOnlySpan<byte> configData) { - //Get the console handler method from the plugin instance - MethodInfo? confHan = PluginType.GetMethods().Where(static m => m.GetCustomAttribute<ConfigurationInitalizerAttribute>() != null) - .FirstOrDefault(); - //Get a delegate handler for the plugin - ConfigInitializer? configInit = confHan?.CreateDelegate<ConfigInitializer>(Plugin); - if (configInit == null) - { - return; - } - - //Invoke - configInit.Invoke(configData); + ManagedLibrary.GetMethodsWithAttribute<ConfigurationInitalizerAttribute, ConfigInitializer>(Plugin!) + .FirstOrDefault() + ?.Invoke(configData); } /// <summary> @@ -118,15 +106,9 @@ namespace VNLib.Plugins.Runtime /// <param name="cliArgs">The current process's CLI args</param> internal void InitLog(string[] cliArgs) { - //Get the console handler method from the plugin instance - MethodInfo? logInit = (from m in PluginType.GetMethods() - where m.GetCustomAttribute<LogInitializerAttribute>() != null - select m) - .FirstOrDefault(); - //Get a delegate handler for the plugin - LogInitializer? logFunc = logInit?.CreateDelegate<LogInitializer>(Plugin); - //Invoke - logFunc?.Invoke(cliArgs); + ManagedLibrary.GetMethodsWithAttribute<LogInitializerAttribute, LogInitializer>(Plugin!) + .FirstOrDefault() + ?.Invoke(cliArgs); } /// <summary> diff --git a/lib/Utils/src/Resources/ManagedLibrary.cs b/lib/Utils/src/Resources/ManagedLibrary.cs index c899156..5faaa19 100644 --- a/lib/Utils/src/Resources/ManagedLibrary.cs +++ b/lib/Utils/src/Resources/ManagedLibrary.cs @@ -263,7 +263,8 @@ namespace VNLib.Utils.Resources /// <param name="flags">The optional method binind flags</param> /// <returns>The delegate if found <see langword="null"/> otherwise</returns> /// <exception cref="ArgumentNullException"></exception> - public static TDelegate? TryGetStaticMethod<TDelegate>(Type type, string methodName, BindingFlags flags = BindingFlags.Public) where TDelegate : Delegate + public static TDelegate? TryGetStaticMethod<TDelegate>(Type type, string methodName, BindingFlags flags = BindingFlags.Public) + where TDelegate : Delegate => TryGetMethodInternal<TDelegate>(type, methodName, null, flags | BindingFlags.Static); /// <summary> @@ -276,7 +277,8 @@ namespace VNLib.Utils.Resources /// <param name="flags">The optional method binind flags</param> /// <returns>The delegate if found <see langword="null"/> otherwise</returns> /// <exception cref="ArgumentNullException"></exception> - public static TDelegate? TryGetStaticMethod<TDelegate, TType>(string methodName,BindingFlags flags = BindingFlags.Public) where TDelegate : Delegate + public static TDelegate? TryGetStaticMethod<TDelegate, TType>(string methodName,BindingFlags flags = BindingFlags.Public) + where TDelegate : Delegate => TryGetMethodInternal<TDelegate>(typeof(TType), methodName, null, flags | BindingFlags.Static); private static TDelegate? TryGetMethodInternal<TDelegate>(Type type, string methodName, object? target, BindingFlags flags) where TDelegate : Delegate @@ -293,5 +295,79 @@ namespace VNLib.Utils.Resources return type.GetMethod(methodName, flags, delegateArgs) ?.CreateDelegate<TDelegate>(target); } + + /* + * NOTE: These functions cannot be optimized (condensed) any furhter. IE: static + * and instance method searches. This is because the C# compiler will embed the + * call to getType() of the object instead of loading reflection if possible + * at runtime. This can cause the type to be undefined at runtime and will not + * be able to find some members + */ + + /// <summary> + /// Gets an array of methods that have the specified attribute and match the + /// delegate signature of the desired type, and returns them as an array of delegates. + /// </summary> + /// <typeparam name="TAttr">The function attribute type</typeparam> + /// <typeparam name="TFunc">The function delegate type</typeparam> + /// <param name="obj">The object instance to get the method delegates for</param> + /// <param name="flags">The method binding flags to search for</param> + /// <returns>An array of function with the desired attribute assigned, an empty array if no methods are found</returns> + public static TFunc[] GetMethodsWithAttribute<TAttr, TFunc>(object obj, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance) + where TFunc : Delegate + where TAttr : Attribute + { + ArgumentNullException.ThrowIfNull(obj); + + //Get the delegate type + Type funcType = typeof(TFunc); + + //Get the delegate method signature + Type[] delegateArgs = funcType.GetMethod("Invoke")! + .GetParameters() + .Select(static p => p.ParameterType) + .ToArray(); + + //Get the method with the attribute that matches the same signature as the delegate + return obj.GetType() + .GetMethods(flags) + .Where(static m => m.GetCustomAttribute(typeof(TAttr)) != null) + .Where(m => m.GetParameters().Select(static p => p.ParameterType).SequenceEqual(delegateArgs)) + .Select(method => method.CreateDelegate<TFunc>(obj)) + .ToArray(); + } + + /// <summary> + /// Gets an array of static methods that have the specified attribute and match the + /// delegate signature of the desired type, and returns them as an array of delegates. + /// </summary> + /// <typeparam name="TAttr">The function attribute type</typeparam> + /// <typeparam name="TFunc">The function delegate type</typeparam> + /// <param name="classType">Type of the static class to get methods for</param> + /// <param name="flags">The method binding flags to search for</param> + /// <returns>An array of function with the desired attribute assigned, an empty array if no methods are found</returns> + public static TFunc[] GetStaticMethodsWithAttribute<TAttr, TFunc>(Type classType, BindingFlags flags = BindingFlags.Public | BindingFlags.Static) + where TFunc : Delegate + where TAttr : Attribute + { + ArgumentNullException.ThrowIfNull(classType); + + //Get the delegate type + Type funcType = typeof(TFunc); + + //Get the delegate method signature + Type[] delegateArgs = funcType.GetMethod("Invoke")! + .GetParameters() + .Select(static p => p.ParameterType) + .ToArray(); + + //Get the method with the attribute that matches the same signature as the delegate + return classType.GetType() + .GetMethods(flags) + .Where(static m => m.GetCustomAttribute(typeof(TAttr)) != null) + .Where(m => m.GetParameters().Select(static p => p.ParameterType).SequenceEqual(delegateArgs)) + .Select(method => method.CreateDelegate<TFunc>(null)) + .ToArray(); + } } } |