|
|
@ -16,19 +16,18 @@ using Boolean = IPA.Config.Data.Boolean; |
|
|
|
using System.Collections; |
|
|
|
using IPA.Utilities; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.Collections.Concurrent; |
|
|
|
#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<Type, (GeneratedStoreCreator ctor, Type type)> generatedCreators = new Dictionary<Type, (GeneratedStoreCreator ctor, Type type)>(); |
|
|
|
|
|
|
|
public static T Create<T>() where T : class => (T)Create(typeof(T)); |
|
|
|
|
|
|
|
public static IConfigStore Create(Type type) => Create(type, null); |
|
|
@ -39,31 +38,44 @@ namespace IPA.Config.Stores |
|
|
|
internal static T Create<T>(IGeneratedStore parent) where T : class => (T)Create(typeof(T), parent); |
|
|
|
|
|
|
|
private static IConfigStore Create(Type type, IGeneratedStore parent) |
|
|
|
=> GetCreator(type)(parent); |
|
|
|
=> GetCreator(type)(parent); |
|
|
|
|
|
|
|
private static readonly ConcurrentDictionary<Type, (ManualResetEventSlim wh, GeneratedStoreCreator ctor, Type type)> generatedCreators |
|
|
|
= new ConcurrentDictionary<Type, (ManualResetEventSlim wh, GeneratedStoreCreator ctor, Type type)>(); |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
private static (GeneratedStoreCreator ctor, Type type) GetCreatorAndGeneratedType(Type t) |
|
|
|
{ |
|
|
|
retry: |
|
|
|
if (generatedCreators.TryGetValue(t, out var gen)) |
|
|
|
{ |
|
|
|
if (gen.wh != null) |
|
|
|
{ |
|
|
|
gen.wh.Wait(); |
|
|
|
goto retry; // this isn't really a good candidate for a loop
|
|
|
|
// the loop condition will never be hit, and this should only
|
|
|
|
// jump back to the beginning in exceptional situations
|
|
|
|
} |
|
|
|
return (gen.ctor, gen.type); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
var wh = new ManualResetEventSlim(false); |
|
|
|
var cmp = (wh, (GeneratedStoreCreator)null, (Type)null); |
|
|
|
if (!generatedCreators.TryAdd(t, cmp)) |
|
|
|
goto retry; // someone else beat us to the punch, retry getting their value and wait for them
|
|
|
|
var (ctor, type) = MakeCreator(t); |
|
|
|
while (!generatedCreators.TryUpdate(t, (null, ctor, type), cmp)) |
|
|
|
throw new InvalidOperationException("Somehow, multiple MakeCreators started running for the same target type!"); |
|
|
|
wh.Set(); |
|
|
|
return (ctor, type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal static GeneratedStoreCreator GetCreator(Type t) |
|
|
|
=> GetCreatorAndGeneratedType(t).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; |
|
|
|
} |
|
|
|
} |
|
|
|
=> GetCreatorAndGeneratedType(t).type; |
|
|
|
|
|
|
|
internal const string GeneratedAssemblyName = "IPA.Config.Generated"; |
|
|
|
|
|
|
@ -97,47 +109,47 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
return module; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static readonly Dictionary<Type, Dictionary<Type, FieldInfo>> TypeRequiredConverters = new Dictionary<Type, Dictionary<Type, FieldInfo>>(); |
|
|
|
private static void CreateAndInitializeConvertersFor(Type type, IEnumerable<SerializedMemberInfo> structure) |
|
|
|
{ |
|
|
|
if (!TypeRequiredConverters.TryGetValue(type, out var converters)) |
|
|
|
{ |
|
|
|
var converterFieldType = Module.DefineType($"{type.FullName}<Converters>", |
|
|
|
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<Type, FieldInfo>(uniqueConverterTypes.Length); |
|
|
|
|
|
|
|
foreach (var convType in uniqueConverterTypes) |
|
|
|
{ |
|
|
|
var field = converterFieldType.DefineField($"<converter>_{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]; |
|
|
|
} |
|
|
|
|
|
|
|
private static readonly Dictionary<Type, Dictionary<Type, FieldInfo>> TypeRequiredConverters = new Dictionary<Type, Dictionary<Type, FieldInfo>>(); |
|
|
|
private static void CreateAndInitializeConvertersFor(Type type, IEnumerable<SerializedMemberInfo> structure) |
|
|
|
{ |
|
|
|
if (!TypeRequiredConverters.TryGetValue(type, out var converters)) |
|
|
|
{ |
|
|
|
var converterFieldType = Module.DefineType($"{type.FullName}<Converters>", |
|
|
|
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<Type, FieldInfo>(uniqueConverterTypes.Length); |
|
|
|
|
|
|
|
foreach (var convType in uniqueConverterTypes) |
|
|
|
{ |
|
|
|
var field = converterFieldType.DefineField($"<converter>_{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]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |