Browse Source

Implemented all of CustomObjectConverter

pull/46/head
Anairkoen Schno 4 years ago
parent
commit
6e304a5f22
3 changed files with 86 additions and 33 deletions
  1. +42
    -0
      IPA.Loader/Config/Stores/Converters.cs
  2. +28
    -17
      IPA.Loader/Config/Stores/GeneratedStore.cs
  3. +16
    -16
      IPA.Loader/Config/Stores/ValueConverter.cs

+ 42
- 0
IPA.Loader/Config/Stores/Converters.cs View File

@ -34,5 +34,47 @@ namespace IPA.Config.Stores.Converters
null;
}
public class CustomObjectConverter<T> : ValueConverter<T> where T : class
{
private interface IImpl
{
T FromValue(Value value, object parent);
Value ToValue(T obj, object parent);
}
private class Impl<U> : IImpl where U : class, GeneratedStore.IGeneratedStore, T
{
private static readonly GeneratedStore.GeneratedStoreCreator creator = GeneratedStore.GetCreator(typeof(T));
public T FromValue(Value value, object parent)
{ // lots of casting here, but it works i promise
var obj = creator(parent as GeneratedStore.IGeneratedStore) as U;
obj.Deserialize(value);
return obj;
}
public Value ToValue(T obj, object parent)
{
if (obj is GeneratedStore.IGeneratedStore store)
return store.Serialize();
else
return null; // TODO: make this behave sanely instead of just giving null
}
}
private static readonly IImpl impl = (IImpl)Activator.CreateInstance(
typeof(Impl<>).MakeGenericType(GeneratedStore.GetGeneratedType(typeof(T))));
public static T Deserialize(Value value, object parent)
=> impl.FromValue(value, parent);
public static Value Serialize(T obj, object parent)
=> impl.ToValue(obj, parent);
public override T FromValue(Value value, object parent)
=> impl.FromValue(value, parent);
public override Value ToValue(T obj, object parent)
=> impl.ToValue(obj, parent);
}
}

+ 28
- 17
IPA.Loader/Config/Stores/GeneratedStore.cs View File

@ -177,8 +177,7 @@ namespace IPA.Config.Stores
}
}
private static Dictionary<Type, Func<IGeneratedStore, IConfigStore>> generatedCreators = new Dictionary<Type, Func<IGeneratedStore, IConfigStore>>();
private static Dictionary<Type, Dictionary<string, Type>> memberMaps = new Dictionary<Type, Dictionary<string, Type>>();
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));
@ -190,14 +189,29 @@ 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);
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;
}
}
internal static Type GetGeneratedType(Type t)
{
if (generatedCreators.TryGetValue(type, out var creator))
return creator(parent);
if (generatedCreators.TryGetValue(t, out var gen))
return gen.type;
else
{
creator = MakeCreator(type);
generatedCreators.Add(type, creator);
return creator(parent);
gen = MakeCreator(t);
generatedCreators.Add(t, gen);
return gen.type;
}
}
@ -259,8 +273,12 @@ namespace IPA.Config.Stores
public ConstructorInfo Nullable_Construct => Type.GetConstructor(new[] { NullableWrappedType });
}
private static Func<IGeneratedStore, IConfigStore> MakeCreator(Type type)
internal delegate IConfigStore GeneratedStoreCreator(IGeneratedStore parent);
private static (GeneratedStoreCreator ctor, Type type) MakeCreator(Type type)
{
if (!type.IsClass) throw new ArgumentException("Config type is not a class");
var baseCtor = type.GetConstructor(Type.EmptyTypes); // get a default constructor
if (baseCtor == null)
throw new ArgumentException("Config type does not have a public parameterless constructor");
@ -758,18 +776,11 @@ namespace IPA.Config.Stores
var genType = typeBuilder.CreateType();
var parentParam = Expression.Parameter(typeof(IGeneratedStore), "parent");
var creatorDel = Expression.Lambda<Func<IGeneratedStore, IConfigStore>>(
var creatorDel = Expression.Lambda<GeneratedStoreCreator>(
Expression.New(ctor, parentParam), parentParam
).Compile();
{ // register a member map
var dict = new Dictionary<string, Type>();
foreach (var member in structure)
dict.Add(member.Name, member.Type);
memberMaps.Add(type, dict);
}
return creatorDel;
return (creatorDel, genType);
}
private delegate LocalBuilder GetLocal(Type type, int idx = 0);


+ 16
- 16
IPA.Loader/Config/Stores/ValueConverter.cs View File

@ -1,9 +1,5 @@
using IPA.Config.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config.Stores
{
@ -12,10 +8,10 @@ namespace IPA.Config.Stores
/// <see cref="GeneratedExtension.Generated{T}(Config, bool)"/>.
/// </summary>
/// <remarks>
/// The object returned from <see cref="FromValue(Value)"/>, if fed into <see cref="ToValue(object)"/>,
/// should return equivalent <see cref="Value"/> structures. Similarly, if the result of <see cref="ToValue(object)"/>
/// is fed into <see cref="FromValue(Value)"/>, the resulting object should be equivalent to the one passed to
/// <see cref="ToValue(object)"/>.
/// The object returned from <see cref="FromValue(Value, object)"/>, if fed into <see cref="ToValue(object, object)"/>,
/// should return equivalent <see cref="Value"/> structures. Similarly, if the result of <see cref="ToValue(object, object)"/>
/// is fed into <see cref="FromValue(Value, object)"/>, the resulting object should be equivalent to the one passed to
/// <see cref="ToValue(object, object)"/>.
/// </remarks>
public interface IValueConverter
{
@ -23,14 +19,16 @@ namespace IPA.Config.Stores
/// Converts the given object to a <see cref="Value"/>.
/// </summary>
/// <param name="obj">the object to convert</param>
/// <param name="parent">the owning object of <paramref name="obj"/></param>
/// <returns>a representation of <paramref name="obj"/> as a <see cref="Value"/> structure</returns>
Value ToValue(object obj);
Value ToValue(object obj, object parent);
/// <summary>
/// Converts the given <see cref="Value"/> to the object type handled by this converter.
/// </summary>
/// <param name="value">the <see cref="Value"/> to deserialize</param>
/// <param name="parent">the object that will own the result</param>
/// <returns>the deserialized object</returns>
object FromValue(Value value);
object FromValue(Value value, object parent);
/// <summary>
/// Gets the type that this <see cref="IValueConverter"/> handles.
/// </summary>
@ -48,19 +46,21 @@ namespace IPA.Config.Stores
/// Converts the given object to a <see cref="Value"/>.
/// </summary>
/// <param name="obj">the object to convert</param>
/// <param name="parent">the owning object of <paramref name="obj"/></param>
/// <returns>a representation of <paramref name="obj"/> as a <see cref="Value"/> structure</returns>
/// <seealso cref="IValueConverter.ToValue(object)"/>
public abstract Value ToValue(T obj);
/// <seealso cref="IValueConverter.ToValue"/>
public abstract Value ToValue(T obj, object parent);
/// <summary>
/// Converts the given <see cref="Value"/> to the object type handled by this converter.
/// </summary>
/// <param name="value">the <see cref="Value"/> to deserialize</param>
/// <param name="parent">the object that will own the result</param>
/// <returns>the deserialized object</returns>
/// <seealso cref="IValueConverter.FromValue(Value)"/>
public abstract T FromValue(Value value);
/// <seealso cref="IValueConverter.FromValue"/>
public abstract T FromValue(Value value, object parent);
Value IValueConverter.ToValue(object obj) => ToValue((T)obj);
object IValueConverter.FromValue(Value value) => FromValue(value);
Value IValueConverter.ToValue(object obj, object parent) => ToValue((T)obj, parent);
object IValueConverter.FromValue(Value value, object parent) => FromValue(value, parent);
Type IValueConverter.Type => typeof(T);
}
}

Loading…
Cancel
Save