using IPA.Config.Data; using IPA.Config.Stores.Attributes; using IPA.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.IO; using Boolean = IPA.Config.Data.Boolean; using System.Collections; using IPA.Utilities; using System.ComponentModel; #if NET3 using Net3_Proxy; using Array = Net3_Proxy.Array; #endif [assembly: InternalsVisibleTo(IPA.Config.Stores.GeneratedStore.AssemblyVisibilityTarget)] namespace IPA.Config.Stores { internal static partial class GeneratedStoreImpl { private static readonly Dictionary generatedCreators = new Dictionary(); public static T Create() where T : class => (T)Create(typeof(T)); public static IConfigStore Create(Type type) => Create(type, null); private static readonly MethodInfo CreateGParent = typeof(GeneratedStoreImpl).GetMethod(nameof(Create), BindingFlags.NonPublic | BindingFlags.Static, null, CallingConventions.Any, new[] { typeof(IGeneratedStore) }, Array.Empty()); internal static T Create(IGeneratedStore parent) where T : class => (T)Create(typeof(T), parent); private static IConfigStore Create(Type type, IGeneratedStore parent) => GetCreator(type)(parent); internal static GeneratedStoreCreator GetCreator(Type t) { if (generatedCreators.TryGetValue(t, out var gen)) return gen.ctor; else { gen = MakeCreator(t); generatedCreators.Add(t, gen); return gen.ctor; } } internal static Type GetGeneratedType(Type t) { if (generatedCreators.TryGetValue(t, out var gen)) return gen.type; else { gen = MakeCreator(t); generatedCreators.Add(t, gen); return gen.type; } } internal const string GeneratedAssemblyName = "IPA.Config.Generated"; private static AssemblyBuilder assembly = null; private static AssemblyBuilder Assembly { get { if (assembly == null) { var name = new AssemblyName(GeneratedAssemblyName); assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); } return assembly; } } internal static void DebugSaveAssembly(string file) { Assembly.Save(file); } private static ModuleBuilder module = null; private static ModuleBuilder Module { get { if (module == null) module = Assembly.DefineDynamicModule(Assembly.GetName().Name, Assembly.GetName().Name + ".dll"); return module; } } private static readonly Dictionary> TypeRequiredConverters = new Dictionary>(); private static void CreateAndInitializeConvertersFor(Type type, IEnumerable structure) { if (!TypeRequiredConverters.TryGetValue(type, out var converters)) { var converterFieldType = Module.DefineType($"{type.FullName}", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.AnsiClass); // a static class var uniqueConverterTypes = structure.Where(m => m.HasConverter).Select(m => m.Converter).Distinct().ToArray(); converters = new Dictionary(uniqueConverterTypes.Length); foreach (var convType in uniqueConverterTypes) { var field = converterFieldType.DefineField($"_{convType}", convType, FieldAttributes.FamORAssem | FieldAttributes.InitOnly | FieldAttributes.Static); converters.Add(convType, field); } var cctor = converterFieldType.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes); { var il = cctor.GetILGenerator(); foreach (var kvp in converters) { var typeCtor = kvp.Key.GetConstructor(Type.EmptyTypes); il.Emit(OpCodes.Newobj, typeCtor); il.Emit(OpCodes.Stsfld, kvp.Value); } il.Emit(OpCodes.Ret); } TypeRequiredConverters.Add(type, converters); converterFieldType.CreateType(); } foreach (var member in structure.Where(m => m.HasConverter)) member.ConverterField = converters[member.Converter]; } } }