diff --git a/IPA.Loader/Config/Stores/GeneratedStore.cs b/IPA.Loader/Config/Stores/GeneratedStore.cs index 88643281..95ae467d 100644 --- a/IPA.Loader/Config/Stores/GeneratedStore.cs +++ b/IPA.Loader/Config/Stores/GeneratedStore.cs @@ -8,6 +8,10 @@ using System.Reflection.Emit; using System.Text; using System.Threading; using System.Threading.Tasks; +#if NET3 +using Net3_Proxy; +using Array = Net3_Proxy.Array; +#endif namespace IPA.Config.Stores { @@ -33,8 +37,10 @@ namespace IPA.Config.Stores private readonly AutoResetEvent resetEvent = new AutoResetEvent(false); public WaitHandle SyncObject => resetEvent; + internal static MethodInfo SyncObjectGetMethod = typeof(Impl).GetProperty(nameof(SyncObject)).GetGetMethod(); 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 void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged(); @@ -149,7 +155,7 @@ namespace IPA.Config.Stores 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()); 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); } - #endregion +#endregion - #region Constructor +#region Constructor // takes its parent var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IGeneratedStore) }); { @@ -219,12 +225,13 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Ret); } - #endregion +#endregion const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; 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)); 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_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 implPropGet = typeBuilder.DefineMethod($"{nameof(IGeneratedStore.Impl)}", virtualPropertyMethodAttr, implProp.PropertyType, Type.EmptyTypes); implProp.SetGetMethod(implPropGet); @@ -247,8 +254,8 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Ldfld, implField); // load impl field 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 typePropGet = typeBuilder.DefineMethod($"{nameof(IGeneratedStore.Type)}", virtualPropertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes); typeProp.SetGetMethod(typePropGet); @@ -261,8 +268,8 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Ldfld, typeField); // load impl field 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 parentPropGet = typeBuilder.DefineMethod($"{nameof(IGeneratedStore.Parent)}", virtualPropertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes); parentProp.SetGetMethod(parentPropGet); @@ -275,8 +282,8 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Ldfld, parentField); // load impl field 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 valuesPropGet = typeBuilder.DefineMethod($"{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes); var valuesPropSet = typeBuilder.DefineMethod($"{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, null, new[] { valuesProp.PropertyType }); @@ -301,10 +308,83 @@ namespace IPA.Config.Stores 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($"{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($"{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( "<>Changed", MethodAttributes.Public | MethodAttributes.HideBySig, @@ -340,10 +420,19 @@ namespace IPA.Config.Stores coreChanged = changedMethod; // switch to calling this version instead of just the default } - #endregion +#endregion // TODO: generate overrides for all the virtual properties + var genType = typeBuilder.CreateType(); + + { // register a member map + var dict = new Dictionary(); + foreach (var kvp in structure) + dict.Add(kvp.Key, kvp.Value.Type); + memberMaps.Add(type, dict); + } + return null; } diff --git a/Net3-Proxy/Array.cs b/Net3-Proxy/Array.cs new file mode 100644 index 00000000..8d396dc3 --- /dev/null +++ b/Net3-Proxy/Array.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OgArray = System.Array; + +namespace Net3_Proxy +{ + public static class Array + { + private static class EmptyArray + { + public static readonly T[] Value = new T[0]; + } + + public static T[] Empty() => EmptyArray.Value; + + } +} diff --git a/Net3-Proxy/Net3-Proxy.csproj b/Net3-Proxy/Net3-Proxy.csproj index c46d4293..f8753e7a 100644 --- a/Net3-Proxy/Net3-Proxy.csproj +++ b/Net3-Proxy/Net3-Proxy.csproj @@ -39,6 +39,7 @@ +