diff --git a/IPA.Loader/Config/IConfigStore.cs b/IPA.Loader/Config/IConfigStore.cs
index fc8f7c3b..634617a0 100644
--- a/IPA.Loader/Config/IConfigStore.cs
+++ b/IPA.Loader/Config/IConfigStore.cs
@@ -35,6 +35,10 @@ namespace IPA.Config
/// Writes the config structure stored by the current to the given
/// .
///
+ ///
+ /// The calling code will have entered a read lock on when
+ /// this is called.
+ ///
/// the provider to write to
void WriteTo(IConfigProvider provider);
@@ -42,7 +46,11 @@ namespace IPA.Config
/// Reads the config structure from the given into the current
/// .
///
- ///
+ ///
+ /// The calling code will have entered a write lock on when
+ /// this is called.
+ ///
+ /// the provider to read from
void ReadFrom(IConfigProvider provider);
}
diff --git a/IPA.Loader/Config/Stores/GeneratedStore.cs b/IPA.Loader/Config/Stores/GeneratedStore.cs
index d866739f..f19a193a 100644
--- a/IPA.Loader/Config/Stores/GeneratedStore.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStore.cs
@@ -1,35 +1,206 @@
-using System;
+using IPA.Config.Data;
+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;
namespace IPA.Config.Stores
{
- internal class GeneratedStore
+ internal static class GeneratedStore
{
+ private interface IGeneratedStore
+ {
+ ///
+ /// serializes/deserializes to Value
+ ///
+ Value Values { get; set; }
+ Type Type { get; }
+ IGeneratedStore Parent { get; }
+ Impl Impl { get; }
+ }
+
private class Impl : IConfigStore
{
- public WaitHandle SyncObject { get; private set; } = new AutoResetEvent(false);
+ private IGeneratedStore generated;
+
+ internal static ConstructorInfo Ctor = typeof(Impl).GetConstructor(new[] { typeof(IGeneratedStore) });
+ public Impl(IGeneratedStore store) => generated = store;
+
+ private readonly AutoResetEvent resetEvent = new AutoResetEvent(false);
+ public WaitHandle SyncObject => resetEvent;
+
+ public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim();
+
+ internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged));
+ internal static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged();
+ internal void SignalChanged() => resetEvent.Set();
+
+ internal static MethodInfo ImplTakeReadMethod = typeof(Impl).GetMethod(nameof(ImplTakeRead));
+ internal static void ImplTakeRead(IGeneratedStore s) => FindImpl(s).TakeRead();
+ internal void TakeRead() => WriteSyncObject.EnterReadLock();
+
+ internal static MethodInfo ImplReleaseReadMethod = typeof(Impl).GetMethod(nameof(ImplReleaseRead));
+ internal static void ImplReleaseRead(IGeneratedStore s) => FindImpl(s).ReleaseRead();
+ internal void ReleaseRead() => WriteSyncObject.ExitWriteLock();
+
+ internal static MethodInfo ImplTakeWriteMethod = typeof(Impl).GetMethod(nameof(ImplTakeWrite));
+ internal static void ImplTakeWrite(IGeneratedStore s) => FindImpl(s).TakeWrite();
+ internal void TakeWrite() => WriteSyncObject.EnterWriteLock();
+
+ internal static MethodInfo ImplReleaseWriteMethod = typeof(Impl).GetMethod(nameof(ImplReleaseWrite));
+ internal static void ImplReleaseWrite(IGeneratedStore s) => FindImpl(s).ReleaseWrite();
+ internal void ReleaseWrite() => WriteSyncObject.ExitWriteLock();
+
+ internal static MethodInfo FindImplMethod = typeof(Impl).GetMethod(nameof(FindImpl));
+ internal static Impl FindImpl(IGeneratedStore store)
+ {
+ while (store != null) store = store.Parent; // walk to the top of the tree
+ return store?.Impl;
+ }
+
- public ReaderWriterLockSlim WriteSyncObject => throw new NotImplementedException();
+ internal static MethodInfo ReadFromMethod = typeof(Impl).GetMethod(nameof(ReadFrom));
public void ReadFrom(IConfigProvider provider)
{
- throw new NotImplementedException();
+ // TODO: implement
}
+ internal static MethodInfo WriteToMethod = typeof(Impl).GetMethod(nameof(WriteTo));
public void WriteTo(IConfigProvider provider)
{
- throw new NotImplementedException();
+ var values = generated.Values;
+ // TODO: implement
}
}
- public static T Create() => (T)Create(typeof(T));
+ private static Dictionary> generatedCreators = new Dictionary>();
+ private static Dictionary> memberMaps = new Dictionary>();
- public static IConfigStore Create(Type type)
+ public static T Create() where T : class => (T)Create(typeof(T));
+
+ public static IConfigStore Create(Type type) => Create(type, null);
+
+ private static IConfigStore Create(Type type, IGeneratedStore parent)
+ {
+ if (generatedCreators.TryGetValue(type, out var creator))
+ return creator(parent);
+ else
+ {
+ creator = MakeCreator(type);
+ generatedCreators.Add(type, creator);
+ return creator(parent);
+ }
+ }
+
+ private static AssemblyBuilder assembly = null;
+ private static AssemblyBuilder Assembly
{
+ get
+ {
+ if (assembly == null)
+ {
+ var name = new AssemblyName("IPA.Config.Generated");
+ assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
+ }
+
+ return assembly;
+ }
+ }
+ private static ModuleBuilder module = null;
+ private static ModuleBuilder Module
+ {
+ get
+ {
+ if (module == null)
+ module = Assembly.DefineDynamicModule(Assembly.GetName().Name);
+
+ return module;
+ }
+ }
+
+ private static Func MakeCreator(Type type)
+ {
+ var typeBuilder = Module.DefineType($"{type.FullName}.Generated",
+ TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class, type);
+
+ var typeField = typeBuilder.DefineField("<>_type", typeof(Type), FieldAttributes.Private | FieldAttributes.InitOnly);
+ var implField = typeBuilder.DefineField("<>_impl", typeof(Impl), FieldAttributes.Private | FieldAttributes.InitOnly);
+ var parentField = typeBuilder.DefineField("<>_parent", typeof(IGeneratedStore), FieldAttributes.Private | FieldAttributes.InitOnly);
+
+ const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
+
+ #region IGeneratedStore
+ typeBuilder.AddInterfaceImplementation(typeof(IGeneratedStore));
+
+ #region IGeneratedStore.Impl
+ var implProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Impl), PropertyAttributes.None, typeof(Impl), null);
+ var implPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Impl)}", propertyMethodAttr, implProp.PropertyType, Type.EmptyTypes);
+ implProp.SetGetMethod(implPropGet);
+
+ {
+ var il = implPropGet.GetILGenerator();
+
+ il.Emit(OpCodes.Ldarg_0); // load this
+ il.Emit(OpCodes.Ldfld, implField); // load impl field
+ il.Emit(OpCodes.Ret);
+ }
+ #endregion
+ #region IGeneratedStore.Type
+ var typeProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Type), PropertyAttributes.None, typeof(Type), null);
+ var typePropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Type)}", propertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes);
+ typeProp.SetGetMethod(typePropGet);
+
+ {
+ var il = typePropGet.GetILGenerator();
+
+ il.Emit(OpCodes.Ldarg_0); // load this
+ il.Emit(OpCodes.Ldfld, typeField); // load impl field
+ il.Emit(OpCodes.Ret);
+ }
+ #endregion
+ #region IGeneratedStore.Parent
+ var parentProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Parent), PropertyAttributes.None, typeof(IGeneratedStore), null);
+ var parentPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Parent)}", propertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes);
+ parentProp.SetGetMethod(parentPropGet);
+
+ {
+ var il = parentPropGet.GetILGenerator();
+
+ il.Emit(OpCodes.Ldarg_0); // load this
+ il.Emit(OpCodes.Ldfld, parentField); // load impl field
+ il.Emit(OpCodes.Ret);
+ }
+ #endregion
+ #region IGeneratedStore.Values
+ var valuesProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Values), PropertyAttributes.None, typeof(Value), null);
+ var valuesPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Values)}", propertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes);
+ var valuesPropSet = typeBuilder.DefineMethod($"set_{nameof(IGeneratedStore.Values)}", propertyMethodAttr, null, new[] { valuesProp.PropertyType });
+ valuesProp.SetGetMethod(valuesPropGet);
+ valuesProp.SetSetMethod(valuesPropSet);
+
+ { // this is non-locking because the only code that will call this will already own the correct lock
+ var il = valuesPropGet.GetILGenerator();
+
+ // TODO: implement get_Values
+ il.Emit(OpCodes.Ldnull);
+
+ il.Emit(OpCodes.Ret);
+ }
+
+ { // this is non-locking because the only code that will call this will already own the correct lock
+ var il = valuesPropSet.GetILGenerator();
+
+ // TODO: implement set_Values
+
+ il.Emit(OpCodes.Ret);
+ }
+ #endregion
+ #endregion
return null;
}