diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs index 16589487..772874b6 100644 --- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs +++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs @@ -119,7 +119,6 @@ namespace IPA.Config.Stores } else { - var Map_TryGetValue = typeof(Map).GetMethod(nameof(Map.TryGetValue)); var mapLocal = GetLocal(typeof(Map)); var resultLocal = GetLocal(targetType, 1); @@ -141,37 +140,10 @@ namespace IPA.Config.Stores EmitLoad(il, member, thisarg); il.Emit(OpCodes.Stloc, resultLocal); - // TODO: pull this and the MakeCreator version out into another function - var nextLabel = il.DefineLabel(); - - // head of stack is Map instance - foreach (var mem in structure) - { - il.MarkLabel(nextLabel); - nextLabel = il.DefineLabel(); - var endErrorLabel = il.DefineLabel(); - - il.Emit(OpCodes.Ldloc, mapLocal); - il.Emit(OpCodes.Ldstr, mem.Name); - il.Emit(OpCodes.Ldloca_S, valueLocal); - il.Emit(OpCodes.Call, Map_TryGetValue); - il.Emit(OpCodes.Brtrue_S, endErrorLabel); - - EmitLogError(il, $"Missing key {mem.Name}", tailcall: false); - il.Emit(OpCodes.Br, nextLabel); - - il.MarkLabel(endErrorLabel); - - il.Emit(OpCodes.Ldloc_S, valueLocal); - EmitDeserializeMember(il, mem, nextLabel, il => il.Emit(OpCodes.Ldloc_S, valueLocal), GetLocal, il => il.Emit(OpCodes.Ldloca, resultLocal), parentobj); - } - - il.MarkLabel(nextLabel); + EmitDeserializeStructure(il, structure, mapLocal, valueLocal, GetLocal, il => il.Emit(OpCodes.Ldloca, resultLocal), parentobj); } il.Emit(OpCodes.Ldloc, resultLocal); - /*il.Emit(OpCodes.Ldloca, resultLocal); - il.Emit(OpCodes.Ldobj, targetType);*/ } } else @@ -181,6 +153,37 @@ namespace IPA.Config.Stores } } + private static void EmitDeserializeStructure(ILGenerator il, IEnumerable structure, + LocalBuilder mapLocal, LocalBuilder valueLocal, + GetLocal GetLocal, Action thisobj, Action parentobj) + { + var Map_TryGetValue = typeof(Map).GetMethod(nameof(Map.TryGetValue)); + + // head of stack is Map instance + foreach (var mem in structure) + { + var nextLabel = il.DefineLabel(); + + var endErrorLabel = il.DefineLabel(); + + il.Emit(OpCodes.Ldloc, mapLocal); + il.Emit(OpCodes.Ldstr, mem.Name); + il.Emit(OpCodes.Ldloca_S, valueLocal); + il.Emit(OpCodes.Call, Map_TryGetValue); + il.Emit(OpCodes.Brtrue_S, endErrorLabel); + + EmitLogError(il, $"Missing key {mem.Name}", tailcall: false); + il.Emit(OpCodes.Br, nextLabel); + + il.MarkLabel(endErrorLabel); + + il.Emit(OpCodes.Ldloc_S, valueLocal); + EmitDeserializeMember(il, mem, nextLabel, il => il.Emit(OpCodes.Ldloc_S, valueLocal), GetLocal, thisobj, parentobj); + + il.MarkLabel(nextLabel); + } + } + private static void EmitDeserializeConverter(ILGenerator il, SerializedMemberInfo member, Label nextLabel, GetLocal GetLocal, Action thisobj, Action parentobj) { diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs index fa1024d7..4af6c223 100644 --- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs +++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs @@ -422,33 +422,12 @@ namespace IPA.Config.Stores }); il.Emit(OpCodes.Ret); - var nextLabel = notMapError; + il.MarkLabel(notMapError); var GetLocal = MakeGetLocal(il); // head of stack is Map instance - foreach (var member in structure) - { - il.MarkLabel(nextLabel); - nextLabel = il.DefineLabel(); - var endErrorLabel = il.DefineLabel(); - - il.Emit(OpCodes.Ldloc, mapLocal); - il.Emit(OpCodes.Ldstr, member.Name); - il.Emit(OpCodes.Ldloca_S, valueLocal); - il.Emit(OpCodes.Call, Map_TryGetValue); - il.Emit(OpCodes.Brtrue_S, endErrorLabel); - - EmitLogError(il, $"Missing key {member.Name}", tailcall: false); - il.Emit(OpCodes.Br, nextLabel); - - il.MarkLabel(endErrorLabel); - - il.Emit(OpCodes.Ldloc_S, valueLocal); - EmitDeserializeMember(il, member, nextLabel, il => il.Emit(OpCodes.Ldloc_S, valueLocal), GetLocal, GetMethodThis, GetMethodThis); - } - - il.MarkLabel(nextLabel); + EmitDeserializeStructure(il, structure, mapLocal, valueLocal, GetLocal, GetMethodThis, GetMethodThis); if (notifyChanged != null) { @@ -774,8 +753,7 @@ namespace IPA.Config.Stores var memberType = member.ConversionType; var expectType = GetExpectedValueTypeForType(memberType); - // if we expect a map, and the type is *not* a value type, it can be converted - if (expectType == typeof(Map) && !memberType.IsValueType) // TODO: make this slightly saner + if (expectType == typeof(Map)) // TODO: make this slightly saner return true; return false; } @@ -785,7 +763,6 @@ namespace IPA.Config.Stores Action thisobj, Action parentobj) { if (!NeedsCorrection(member)) return; - // this will never be called for a custom value type var endLabel = il.DefineLabel(); @@ -797,37 +774,40 @@ namespace IPA.Config.Stores il.Emit(OpCodes.Call, member.Nullable_Value.GetGetMethod()); } - // TODO: impl the rest of this + if (!member.ConversionType.IsValueType) + { + // currently the only thing for this is where expect == Map, so do generate shit + var copyFrom = typeof(IGeneratedStore<>).MakeGenericType(member.ConversionType).GetMethod(nameof(IGeneratedStore.CopyFrom)); + var noCreate = il.DefineLabel(); + var valLocal = GetLocal(member.Type); - // currently the only thing for this is where expect == Map, so do generate shit - var copyFrom = typeof(IGeneratedStore<>).MakeGenericType(member.Type).GetMethod(nameof(IGeneratedStore.CopyFrom)); - var noCreate = il.DefineLabel(); - var valLocal = GetLocal(member.Type); + if (!alwaysNew) + { + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, endLabel); // our input is already something we like + } + il.Emit(OpCodes.Stloc, valLocal); + if (!alwaysNew) + { + EmitLoad(il, member, thisobj); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); + il.Emit(OpCodes.Brtrue_S, noCreate); + il.Emit(OpCodes.Pop); + } + EmitCreateChildGenerated(il, member.Type, parentobj); + il.MarkLabel(noCreate); - if (!alwaysNew) - { il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, endLabel); // our input is already something we like + il.Emit(OpCodes.Ldloc, valLocal); + il.Emit(shouldLock ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Callvirt, copyFrom); } - il.Emit(OpCodes.Stloc, valLocal); - if (!alwaysNew) + else { - EmitLoad(il, member, thisobj); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Isinst, typeof(IGeneratedStore)); - il.Emit(OpCodes.Brtrue_S, noCreate); - il.Emit(OpCodes.Pop); + // TODO: impl the rest of this } - EmitCreateChildGenerated(il, member.Type, parentobj); - il.MarkLabel(noCreate); - - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldloc, valLocal); - il.Emit(shouldLock ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Callvirt, copyFrom); - - // TODO: impl the rest of this if (member.IsNullable) il.Emit(OpCodes.Newobj, member.Nullable_Construct);