mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-01 17:47:24 +02:00
* Add source generator for DataDefinition validation * Add source generator for reading * Add source generator for writing * Include prototypes and other meansdatadefinition types * Target ISerializationGenerated in data definitions * Murder * Use array, struct, enum methods * Source generate get field definitions * serv5 * Fix and pray * Fix release compile * Tayrtahn review * a * Generator bugfix --------- Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
89 lines
2.8 KiB
C#
89 lines
2.8 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using Robust.Shared.Serialization.Manager.Definition;
|
|
|
|
namespace Robust.Shared.Utility;
|
|
|
|
internal static class InternalReflectionUtils
|
|
{
|
|
internal delegate TValue AccessField<TTarget, TValue>(ref TTarget target);
|
|
|
|
internal delegate void AssignField<TTarget, TValue>(ref TTarget target, TValue? value);
|
|
|
|
|
|
private static void EmitSetField(ILGenerator rGenerator, AbstractFieldInfo info)
|
|
{
|
|
switch (info)
|
|
{
|
|
case SpecificFieldInfo field:
|
|
rGenerator.Emit(OpCodes.Stfld, field.FieldInfo);
|
|
break;
|
|
case SpecificPropertyInfo property:
|
|
if (property.GetBackingField() is { } backingField)
|
|
{
|
|
rGenerator.Emit(OpCodes.Stfld, backingField.FieldInfo);
|
|
break;
|
|
}
|
|
|
|
var setter = property.PropertyInfo.GetSetMethod(true) ?? throw new NullReferenceException();
|
|
|
|
var opCode = info.DeclaringType?.IsValueType ?? false
|
|
? OpCodes.Call
|
|
: OpCodes.Callvirt;
|
|
|
|
rGenerator.Emit(opCode, setter);
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal static object EmitFieldAssigner(Type objType, AbstractFieldInfo backingField, bool boxing = false)
|
|
{
|
|
if (!boxing)
|
|
{
|
|
if (backingField is SpecificFieldInfo { FieldInfo.IsInitOnly: false } fieldInfo)
|
|
return fieldInfo.FieldInfo;
|
|
|
|
if (backingField is SpecificPropertyInfo propertyInfo)
|
|
{
|
|
if (propertyInfo.TryGetBackingField(out var propertyBackingField) && !propertyBackingField.FieldInfo.IsInitOnly)
|
|
return propertyBackingField.FieldInfo;
|
|
|
|
if (propertyInfo.PropertyInfo.GetSetMethod(true) is { } setMethod)
|
|
return setMethod;
|
|
}
|
|
}
|
|
|
|
var fieldType = backingField.FieldType;
|
|
|
|
var method = new DynamicMethod(
|
|
"AssignField",
|
|
typeof(void),
|
|
new[] {objType.MakeByRefType(), boxing ? typeof(object) : fieldType},
|
|
true);
|
|
|
|
method.DefineParameter(1, ParameterAttributes.Out, "target");
|
|
method.DefineParameter(2, ParameterAttributes.None, "value");
|
|
|
|
var generator = method.GetILGenerator();
|
|
|
|
generator.Emit(OpCodes.Ldarg_0);
|
|
|
|
if(!objType.IsValueType)
|
|
generator.Emit(OpCodes.Ldind_Ref);
|
|
|
|
generator.Emit(OpCodes.Ldarg_1);
|
|
|
|
if (boxing)
|
|
{
|
|
generator.Emit(fieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, fieldType);
|
|
}
|
|
|
|
EmitSetField(generator, backingField);
|
|
|
|
generator.Emit(OpCodes.Ret);
|
|
|
|
return method.CreateDelegate(typeof(AssignField<,>).MakeGenericType(objType, boxing ? typeof(object) : fieldType));
|
|
}
|
|
}
|