Browse Source

Added support for converters

4.0.0-beta
Anairkoen Schno 5 years ago
parent
commit
b948ca60ec
1 changed files with 75 additions and 6 deletions
  1. +75
    -6
      IPA.Loader/Config/Stores/GeneratedStore.cs

+ 75
- 6
IPA.Loader/Config/Stores/GeneratedStore.cs View File

@ -262,6 +262,7 @@ namespace IPA.Config.Stores
public bool HasConverter; public bool HasConverter;
public bool IsGenericConverter; // used so we can call directly to the generic version if it is public bool IsGenericConverter; // used so we can call directly to the generic version if it is
public Type Converter; public Type Converter;
public Type ConverterBase;
public Type ConverterTarget; public Type ConverterTarget;
public FieldInfo ConverterField; public FieldInfo ConverterField;
@ -371,6 +372,10 @@ namespace IPA.Config.Stores
} }
member.ConverterTarget = targetType; member.ConverterTarget = targetType;
if (member.IsGenericConverter)
member.ConverterBase = typeof(ValueConverter<>).MakeGenericType(targetType);
else
member.ConverterBase = typeof(IValueConverter);
member.HasConverter = true; member.HasConverter = true;
} }
@ -1083,7 +1088,35 @@ namespace IPA.Config.Stores
il.Emit(OpCodes.Call, member.Nullable_Value.GetGetMethod()); il.Emit(OpCodes.Call, member.Nullable_Value.GetGetMethod());
var targetType = GetExpectedValueTypeForType(member.Type); var targetType = GetExpectedValueTypeForType(member.Type);
if (targetType == typeof(Text))
if (member.HasConverter)
{
var stlocal = GetLocal(member.Type);
if (member.IsGenericConverter)
{
var toValue = member.ConverterBase.GetMethod(nameof(ValueConverter<int>.ToValue),
new[] { member.ConverterTarget, typeof(object) });
il.Emit(OpCodes.Stloc, stlocal);
il.Emit(OpCodes.Ldsfld, member.ConverterField);
il.Emit(OpCodes.Ldloc, stlocal);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, toValue);
}
else
{
var toValue = typeof(IValueConverter).GetMethod(nameof(IValueConverter.ToValue),
new[] { typeof(object), typeof(object) });
il.Emit(OpCodes.Stloc, stlocal);
il.Emit(OpCodes.Ldsfld, member.ConverterField);
il.Emit(OpCodes.Ldloc, stlocal);
if (member.Type.IsValueType)
il.Emit(OpCodes.Box);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, toValue);
}
}
else if (targetType == typeof(Text))
{ // only happens when arg is a string or char { // only happens when arg is a string or char
var TextCreate = typeof(Value).GetMethod(nameof(Value.Text)); var TextCreate = typeof(Value).GetMethod(nameof(Value.Text));
if (member.Type == typeof(char)) if (member.Type == typeof(char))
@ -1224,6 +1257,35 @@ namespace IPA.Config.Stores
} }
} }
private static void EmitDeserializeConverter(ILGenerator il, SerializedMemberInfo member, GetLocal GetLocal)
{
var stlocal = GetLocal(typeof(Value));
if (member.IsGenericConverter)
{
var fromValue = member.ConverterBase.GetMethod(nameof(ValueConverter<int>.FromValue),
new[] { typeof(Value), typeof(object) });
il.Emit(OpCodes.Stloc, stlocal);
il.Emit(OpCodes.Ldsfld, member.ConverterField);
il.Emit(OpCodes.Ldloc, stlocal);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, fromValue);
}
else
{
var fromValue = typeof(IValueConverter).GetMethod(nameof(IValueConverter.FromValue),
new[] { typeof(Value), typeof(object) });
il.Emit(OpCodes.Stloc, stlocal);
il.Emit(OpCodes.Ldsfld, member.ConverterField);
il.Emit(OpCodes.Ldloc, stlocal);
if (member.Type.IsValueType)
il.Emit(OpCodes.Box);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, fromValue);
}
}
// emit takes the value being deserialized, logs on error, leaves nothing on stack // emit takes the value being deserialized, logs on error, leaves nothing on stack
private static void EmitDeserializeMember(ILGenerator il, SerializedMemberInfo member, Label nextLabel, Action<ILGenerator> getValue, GetLocal GetLocal) private static void EmitDeserializeMember(ILGenerator il, SerializedMemberInfo member, Label nextLabel, Action<ILGenerator> getValue, GetLocal GetLocal)
{ {
@ -1261,14 +1323,20 @@ namespace IPA.Config.Stores
il.MarkLabel(implLabel); il.MarkLabel(implLabel);
il.Emit(OpCodes.Isinst, expectType); //replaces on stack
il.Emit(OpCodes.Dup); // duplicate cloned value
il.Emit(OpCodes.Brtrue, passedTypeCheck); // null check
if (member.HasConverter)
il.Emit(OpCodes.Br, passedTypeCheck);
else
{
il.Emit(OpCodes.Isinst, expectType); //replaces on stack
il.Emit(OpCodes.Dup); // duplicate cloned value
il.Emit(OpCodes.Brtrue, passedTypeCheck); // null check
}
var errorHandle = il.DefineLabel(); var errorHandle = il.DefineLabel();
// special cases to handle coersion between Float and Int // special cases to handle coersion between Float and Int
if (expectType == typeof(FloatingPoint))
if (member.HasConverter) { } // do nothing here
else if (expectType == typeof(FloatingPoint))
{ {
var specialTypeCheck = il.DefineLabel(); var specialTypeCheck = il.DefineLabel();
il.Emit(OpCodes.Pop); il.Emit(OpCodes.Pop);
@ -1310,7 +1378,8 @@ namespace IPA.Config.Stores
il.MarkLabel(passedTypeCheck); il.MarkLabel(passedTypeCheck);
var local = GetLocal(member.Type, 0); var local = GetLocal(member.Type, 0);
if (member.IsNullable) EmitDeserializeNullable(il, member, expectType, GetLocal);
if (member.HasConverter) EmitDeserializeConverter(il, member, GetLocal);
else if (member.IsNullable) EmitDeserializeNullable(il, member, expectType, GetLocal);
else EmitDeserializeValue(il, member.Type, expectType, GetLocal); else EmitDeserializeValue(il, member.Type, expectType, GetLocal);
il.Emit(OpCodes.Stloc, local); il.Emit(OpCodes.Stloc, local);
EmitStore(il, member, il => il.Emit(OpCodes.Ldloc, local)); EmitStore(il, member, il => il.Emit(OpCodes.Ldloc, local));


Loading…
Cancel
Save