|
@ -8,6 +8,10 @@ using System.Reflection.Emit; |
|
|
using System.Text; |
|
|
using System.Text; |
|
|
using System.Threading; |
|
|
using System.Threading; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
|
|
|
#if NET3
|
|
|
|
|
|
using Net3_Proxy; |
|
|
|
|
|
using Array = Net3_Proxy.Array; |
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
namespace IPA.Config.Stores |
|
|
namespace IPA.Config.Stores |
|
|
{ |
|
|
{ |
|
@ -33,8 +37,10 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
private readonly AutoResetEvent resetEvent = new AutoResetEvent(false); |
|
|
private readonly AutoResetEvent resetEvent = new AutoResetEvent(false); |
|
|
public WaitHandle SyncObject => resetEvent; |
|
|
public WaitHandle SyncObject => resetEvent; |
|
|
|
|
|
internal static MethodInfo SyncObjectGetMethod = typeof(Impl).GetProperty(nameof(SyncObject)).GetGetMethod(); |
|
|
|
|
|
|
|
|
public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim(); |
|
|
public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim(); |
|
|
|
|
|
internal static MethodInfo WriteSyncObjectGetMethod = typeof(Impl).GetProperty(nameof(WriteSyncObject)).GetGetMethod(); |
|
|
|
|
|
|
|
|
internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged)); |
|
|
internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged)); |
|
|
internal static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged(); |
|
|
internal static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged(); |
|
@ -149,7 +155,7 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
var GetTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)); |
|
|
var GetTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)); |
|
|
|
|
|
|
|
|
#region Parse base object structure
|
|
|
|
|
|
|
|
|
#region Parse base object structure
|
|
|
var baseChanged = type.GetMethod("Changed", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>()); |
|
|
var baseChanged = type.GetMethod("Changed", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>()); |
|
|
if (baseChanged != null && !baseChanged.IsVirtual) baseChanged = null; // limit this to just the one thing
|
|
|
if (baseChanged != null && !baseChanged.IsVirtual) baseChanged = null; // limit this to just the one thing
|
|
|
|
|
|
|
|
@ -185,9 +191,9 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
structure.Add(smi.Name, smi); |
|
|
structure.Add(smi.Name, smi); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
#region Constructor
|
|
|
|
|
|
|
|
|
#region Constructor
|
|
|
// takes its parent
|
|
|
// takes its parent
|
|
|
var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IGeneratedStore) }); |
|
|
var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IGeneratedStore) }); |
|
|
{ |
|
|
{ |
|
@ -219,12 +225,13 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
il.Emit(OpCodes.Ret); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; |
|
|
const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; |
|
|
const MethodAttributes virtualPropertyMethodAttr = propertyMethodAttr | MethodAttributes.Virtual | MethodAttributes.Final; |
|
|
const MethodAttributes virtualPropertyMethodAttr = propertyMethodAttr | MethodAttributes.Virtual | MethodAttributes.Final; |
|
|
|
|
|
const MethodAttributes virtualMemberMethod = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Final; |
|
|
|
|
|
|
|
|
#region IGeneratedStore
|
|
|
|
|
|
|
|
|
#region IGeneratedStore
|
|
|
typeBuilder.AddInterfaceImplementation(typeof(IGeneratedStore)); |
|
|
typeBuilder.AddInterfaceImplementation(typeof(IGeneratedStore)); |
|
|
|
|
|
|
|
|
var IGeneratedStore_t = typeof(IGeneratedStore); |
|
|
var IGeneratedStore_t = typeof(IGeneratedStore); |
|
@ -234,7 +241,7 @@ namespace IPA.Config.Stores |
|
|
var IGeneratedStore_GetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetGetMethod(); |
|
|
var IGeneratedStore_GetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetGetMethod(); |
|
|
var IGeneratedStore_SetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetSetMethod(); |
|
|
var IGeneratedStore_SetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetSetMethod(); |
|
|
|
|
|
|
|
|
#region IGeneratedStore.Impl
|
|
|
|
|
|
|
|
|
#region IGeneratedStore.Impl
|
|
|
var implProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Impl), PropertyAttributes.None, typeof(Impl), null); |
|
|
var implProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Impl), PropertyAttributes.None, typeof(Impl), null); |
|
|
var implPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Impl)}", virtualPropertyMethodAttr, implProp.PropertyType, Type.EmptyTypes); |
|
|
var implPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Impl)}", virtualPropertyMethodAttr, implProp.PropertyType, Type.EmptyTypes); |
|
|
implProp.SetGetMethod(implPropGet); |
|
|
implProp.SetGetMethod(implPropGet); |
|
@ -247,8 +254,8 @@ namespace IPA.Config.Stores |
|
|
il.Emit(OpCodes.Ldfld, implField); // load impl field
|
|
|
il.Emit(OpCodes.Ldfld, implField); // load impl field
|
|
|
il.Emit(OpCodes.Ret); |
|
|
il.Emit(OpCodes.Ret); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Type
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Type
|
|
|
var typeProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Type), PropertyAttributes.None, typeof(Type), null); |
|
|
var typeProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Type), PropertyAttributes.None, typeof(Type), null); |
|
|
var typePropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Type)}", virtualPropertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes); |
|
|
var typePropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Type)}", virtualPropertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes); |
|
|
typeProp.SetGetMethod(typePropGet); |
|
|
typeProp.SetGetMethod(typePropGet); |
|
@ -261,8 +268,8 @@ namespace IPA.Config.Stores |
|
|
il.Emit(OpCodes.Ldfld, typeField); // load impl field
|
|
|
il.Emit(OpCodes.Ldfld, typeField); // load impl field
|
|
|
il.Emit(OpCodes.Ret); |
|
|
il.Emit(OpCodes.Ret); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Parent
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Parent
|
|
|
var parentProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Parent), PropertyAttributes.None, typeof(IGeneratedStore), null); |
|
|
var parentProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Parent), PropertyAttributes.None, typeof(IGeneratedStore), null); |
|
|
var parentPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Parent)}", virtualPropertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes); |
|
|
var parentPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Parent)}", virtualPropertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes); |
|
|
parentProp.SetGetMethod(parentPropGet); |
|
|
parentProp.SetGetMethod(parentPropGet); |
|
@ -275,8 +282,8 @@ namespace IPA.Config.Stores |
|
|
il.Emit(OpCodes.Ldfld, parentField); // load impl field
|
|
|
il.Emit(OpCodes.Ldfld, parentField); // load impl field
|
|
|
il.Emit(OpCodes.Ret); |
|
|
il.Emit(OpCodes.Ret); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Values
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IGeneratedStore.Values
|
|
|
var valuesProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Values), PropertyAttributes.None, typeof(Value), null); |
|
|
var valuesProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Values), PropertyAttributes.None, typeof(Value), null); |
|
|
var valuesPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes); |
|
|
var valuesPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes); |
|
|
var valuesPropSet = typeBuilder.DefineMethod($"<s>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, null, new[] { valuesProp.PropertyType }); |
|
|
var valuesPropSet = typeBuilder.DefineMethod($"<s>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, null, new[] { valuesProp.PropertyType }); |
|
@ -301,10 +308,83 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
il.Emit(OpCodes.Ret); |
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
#region Changed
|
|
|
|
|
|
|
|
|
#region IConfigStore
|
|
|
|
|
|
typeBuilder.AddInterfaceImplementation(typeof(IConfigStore)); |
|
|
|
|
|
|
|
|
|
|
|
var IConfigStore_t = typeof(IConfigStore); |
|
|
|
|
|
var IConfigStore_GetSyncObject = IConfigStore_t.GetProperty(nameof(IConfigStore.SyncObject)).GetGetMethod(); |
|
|
|
|
|
var IConfigStore_GetWriteSyncObject = IConfigStore_t.GetProperty(nameof(IConfigStore.WriteSyncObject)).GetGetMethod(); |
|
|
|
|
|
var IConfigStore_WriteTo = IConfigStore_t.GetMethod(nameof(IConfigStore.WriteTo)); |
|
|
|
|
|
var IConfigStore_ReadFrom = IConfigStore_t.GetMethod(nameof(IConfigStore.ReadFrom)); |
|
|
|
|
|
|
|
|
|
|
|
#region IConfigStore.SyncObject
|
|
|
|
|
|
var syncObjProp = typeBuilder.DefineProperty(nameof(IConfigStore.SyncObject), PropertyAttributes.None, typeof(WaitHandle), null); |
|
|
|
|
|
var syncObjPropGet = typeBuilder.DefineMethod($"<g>{nameof(IConfigStore.SyncObject)}", virtualPropertyMethodAttr, syncObjProp.PropertyType, Type.EmptyTypes); |
|
|
|
|
|
syncObjProp.SetGetMethod(syncObjPropGet); |
|
|
|
|
|
typeBuilder.DefineMethodOverride(syncObjPropGet, IConfigStore_GetSyncObject); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
var il = syncObjPropGet.GetILGenerator(); |
|
|
|
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ldarg_0); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.FindImplMethod); |
|
|
|
|
|
il.Emit(OpCodes.Tailcall); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.SyncObjectGetMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IConfigStore.WriteSyncObject
|
|
|
|
|
|
var writeSyncObjProp = typeBuilder.DefineProperty(nameof(IConfigStore.WriteSyncObject), PropertyAttributes.None, typeof(WaitHandle), null); |
|
|
|
|
|
var writeSyncObjPropGet = typeBuilder.DefineMethod($"<g>{nameof(IConfigStore.WriteSyncObject)}", virtualPropertyMethodAttr, writeSyncObjProp.PropertyType, Type.EmptyTypes); |
|
|
|
|
|
writeSyncObjProp.SetGetMethod(writeSyncObjPropGet); |
|
|
|
|
|
typeBuilder.DefineMethodOverride(writeSyncObjPropGet, IConfigStore_GetWriteSyncObject); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
var il = writeSyncObjPropGet.GetILGenerator(); |
|
|
|
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ldarg_0); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.FindImplMethod); |
|
|
|
|
|
il.Emit(OpCodes.Tailcall); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.WriteSyncObjectGetMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IConfigStore.WriteTo
|
|
|
|
|
|
var writeTo = typeBuilder.DefineMethod($"<>{nameof(IConfigStore.WriteTo)}", virtualMemberMethod, null, new[] { typeof(IConfigProvider) }); |
|
|
|
|
|
typeBuilder.DefineMethodOverride(writeTo, IConfigStore_WriteTo); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
var il = writeTo.GetILGenerator(); |
|
|
|
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ldarg_0); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.FindImplMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ldarg_1); |
|
|
|
|
|
il.Emit(OpCodes.Tailcall); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.WriteToMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region IConfigStore.ReadFrom
|
|
|
|
|
|
var readFrom = typeBuilder.DefineMethod($"<>{nameof(IConfigStore.ReadFrom)}", virtualMemberMethod, null, new[] { typeof(IConfigProvider) }); |
|
|
|
|
|
typeBuilder.DefineMethodOverride(readFrom, IConfigStore_ReadFrom); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
var il = writeTo.GetILGenerator(); |
|
|
|
|
|
|
|
|
|
|
|
il.Emit(OpCodes.Ldarg_0); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.FindImplMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ldarg_1); |
|
|
|
|
|
il.Emit(OpCodes.Tailcall); |
|
|
|
|
|
il.Emit(OpCodes.Call, Impl.ReadFromMethod); |
|
|
|
|
|
il.Emit(OpCodes.Ret); |
|
|
|
|
|
} |
|
|
|
|
|
#endregion
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Changed
|
|
|
var coreChanged = typeBuilder.DefineMethod( |
|
|
var coreChanged = typeBuilder.DefineMethod( |
|
|
"<>Changed", |
|
|
"<>Changed", |
|
|
MethodAttributes.Public | MethodAttributes.HideBySig, |
|
|
MethodAttributes.Public | MethodAttributes.HideBySig, |
|
@ -340,10 +420,19 @@ namespace IPA.Config.Stores |
|
|
|
|
|
|
|
|
coreChanged = changedMethod; // switch to calling this version instead of just the default
|
|
|
coreChanged = changedMethod; // switch to calling this version instead of just the default
|
|
|
} |
|
|
} |
|
|
#endregion
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
// TODO: generate overrides for all the virtual properties
|
|
|
// TODO: generate overrides for all the virtual properties
|
|
|
|
|
|
|
|
|
|
|
|
var genType = typeBuilder.CreateType(); |
|
|
|
|
|
|
|
|
|
|
|
{ // register a member map
|
|
|
|
|
|
var dict = new Dictionary<string, Type>(); |
|
|
|
|
|
foreach (var kvp in structure) |
|
|
|
|
|
dict.Add(kvp.Key, kvp.Value.Type); |
|
|
|
|
|
memberMaps.Add(type, dict); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return null; |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|