Browse Source

Added the ability to expose CopyFrom in config

4.0.0-beta
Anairkoen Schno 4 years ago
parent
commit
a1e65bb891
1 changed files with 58 additions and 18 deletions
  1. +58
    -18
      IPA.Loader/Config/Stores/GeneratedStore.cs

+ 58
- 18
IPA.Loader/Config/Stores/GeneratedStore.cs View File

@ -72,6 +72,11 @@ namespace IPA.Config.Stores
/// object of the config structure. /// object of the config structure.
/// </para> /// </para>
/// <para> /// <para>
/// Similarly, <typeparamref name="T"/> can declare a public or protected, <see langword="virtual"/>
/// method <c>CopyFrom(ConfigType)</c> (the first parameter is the type it is defined on), which may be called to copy the properties from
/// another object of its type easily, and more importantly, as only one change. Its body will be executed after the values have been copied.
/// </para>
/// <para>
/// TODO: describe details of generated stores /// TODO: describe details of generated stores
/// </para> /// </para>
/// </remarks> /// </remarks>
@ -120,10 +125,12 @@ 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 static WaitHandle ImplGetSyncObject(IGeneratedStore s) => FindImpl(s).SyncObject;
internal static MethodInfo ImplGetSyncObjectMethod = typeof(Impl).GetMethod(nameof(ImplGetSyncObject));
public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim(); public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim();
internal static MethodInfo WriteSyncObjectGetMethod = typeof(Impl).GetProperty(nameof(WriteSyncObject)).GetGetMethod();
public static ReaderWriterLockSlim ImplGetWriteSyncObject(IGeneratedStore s) => FindImpl(s)?.WriteSyncObject;
internal static MethodInfo ImplGetWriteSyncObjectMethod = typeof(Impl).GetMethod(nameof(ImplGetWriteSyncObject));
internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged)); internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged));
public static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged(); public static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged();
@ -149,7 +156,7 @@ namespace IPA.Config.Stores
public static void ImplReleaseWrite(IGeneratedStore s) => FindImpl(s).ReleaseWrite(); public static void ImplReleaseWrite(IGeneratedStore s) => FindImpl(s).ReleaseWrite();
public void ReleaseWrite() => WriteSyncObject.ExitWriteLock(); public void ReleaseWrite() => WriteSyncObject.ExitWriteLock();
internal static MethodInfo FindImplMethod = typeof(Impl).GetMethod(nameof(FindImpl));
public static Impl FindImpl(IGeneratedStore store) public static Impl FindImpl(IGeneratedStore store)
{ {
while (store?.Parent != null) store = store.Parent; // walk to the top of the tree while (store?.Parent != null) store = store.Parent; // walk to the top of the tree
@ -157,8 +164,8 @@ namespace IPA.Config.Stores
} }
internal static MethodInfo ReadFromMethod = typeof(Impl).GetMethod(nameof(ReadFrom));
internal static MethodInfo ImplReadFromMethod = typeof(Impl).GetMethod(nameof(ImplReadFrom));
public static void ImplReadFrom(IGeneratedStore s, ConfigProvider provider) => FindImpl(s).ReadFrom(provider);
public void ReadFrom(ConfigProvider provider) public void ReadFrom(ConfigProvider provider)
{ {
var values = provider.Load(); var values = provider.Load();
@ -171,7 +178,8 @@ namespace IPA.Config.Stores
TakeWrite(); // must take again for runtime to be happy (which is unfortunate) TakeWrite(); // must take again for runtime to be happy (which is unfortunate)
} }
internal static MethodInfo WriteToMethod = typeof(Impl).GetMethod(nameof(WriteTo));
internal static MethodInfo ImplWriteToMethod = typeof(Impl).GetMethod(nameof(ImplWriteTo));
public static void ImplWriteTo(IGeneratedStore s, ConfigProvider provider) => FindImpl(s).WriteTo(provider);
public void WriteTo(ConfigProvider provider) public void WriteTo(ConfigProvider provider)
{ {
var values = generated.Serialize(); var values = generated.Serialize();
@ -292,9 +300,11 @@ namespace IPA.Config.Stores
#region Parse base object structure #region Parse base object structure
var baseChanged = type.GetMethod("Changed", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>()); var baseChanged = type.GetMethod("Changed", BindingFlags.Public | BindingFlags.NonPublic | 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;
var baseOnReload = type.GetMethod("OnReload", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>()); var baseOnReload = type.GetMethod("OnReload", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>());
if (baseOnReload != null && !baseOnReload.IsVirtual) baseOnReload = null; // limit this to just the one thing
if (baseOnReload != null && !baseOnReload.IsVirtual) baseOnReload = null;
var baseCopyFrom = type.GetMethod("CopyFrom", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { type }, Array.Empty<ParameterModifier>());
if (baseCopyFrom != null && !baseCopyFrom.IsVirtual) baseCopyFrom = null;
var structure = new List<SerializedMemberInfo>(); var structure = new List<SerializedMemberInfo>();
@ -477,10 +487,14 @@ namespace IPA.Config.Stores
EmitTypeof(il, type); EmitTypeof(il, type);
il.Emit(OpCodes.Stfld, typeField); il.Emit(OpCodes.Stfld, typeField);
var noImplLabel = il.DefineLabel();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Brtrue, noImplLabel);
il.Emit(OpCodes.Dup); il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Dup); il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Newobj, Impl.Ctor); il.Emit(OpCodes.Newobj, Impl.Ctor);
il.Emit(OpCodes.Stfld, implField); il.Emit(OpCodes.Stfld, implField);
il.MarkLabel(noImplLabel);
var GetLocal = MakeGetLocal(il); var GetLocal = MakeGetLocal(il);
@ -735,9 +749,8 @@ namespace IPA.Config.Stores
var il = syncObjPropGet.GetILGenerator(); var il = syncObjPropGet.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, Impl.FindImplMethod);
il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, Impl.SyncObjectGetMethod);
il.Emit(OpCodes.Call, Impl.ImplGetSyncObjectMethod);
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
} }
#endregion #endregion
@ -751,9 +764,8 @@ namespace IPA.Config.Stores
var il = writeSyncObjPropGet.GetILGenerator(); var il = writeSyncObjPropGet.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, Impl.FindImplMethod);
il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, Impl.WriteSyncObjectGetMethod);
il.Emit(OpCodes.Call, Impl.ImplGetWriteSyncObjectMethod);
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
} }
#endregion #endregion
@ -765,10 +777,9 @@ namespace IPA.Config.Stores
var il = writeTo.GetILGenerator(); var il = writeTo.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, Impl.FindImplMethod);
il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, Impl.WriteToMethod);
il.Emit(OpCodes.Call, Impl.ImplWriteToMethod);
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
} }
#endregion #endregion
@ -780,10 +791,9 @@ namespace IPA.Config.Stores
var il = readFrom.GetILGenerator(); var il = readFrom.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, Impl.FindImplMethod);
il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, Impl.ReadFromMethod);
il.Emit(OpCodes.Call, Impl.ImplReadFromMethod);
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
} }
#endregion #endregion
@ -826,9 +836,39 @@ 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
} }
typeBuilder.DefineMethodOverride(coreChanged, IGeneratedStore_Changed);
typeBuilder.DefineMethodOverride(coreChanged, IGeneratedStore_Changed);
#endregion #endregion
#region base.CopyFrom
if (baseCopyFrom != null)
{
var pubCopyFrom = typeBuilder.DefineMethod(
baseCopyFrom.Name,
virtualMemberMethod,
null, new[] { type });
typeBuilder.DefineMethodOverride(pubCopyFrom, baseCopyFrom);
{
var il = pubCopyFrom.GetILGenerator();
// TODO: use transactional changes
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, copyFrom); // call internal
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, baseCopyFrom); // call base
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, coreChanged); // call changed
il.Emit(OpCodes.Ret);
}
}
#endregion
#region Members #region Members
foreach (var member in structure.Where(m => m.IsVirtual)) foreach (var member in structure.Where(m => m.IsVirtual))
{ // IsVirtual implies !IsField { // IsVirtual implies !IsField


Loading…
Cancel
Save