ProtobufTest/Assets/Plugs/protobuf-net/Serializers/FieldDecorator.cs

104 lines
3.8 KiB
C#
Raw Permalink Normal View History

2024-05-08 13:44:40 +08:00
#if !NO_RUNTIME
using System;
using System.Reflection;
namespace ProtoBuf.Serializers
{
sealed class FieldDecorator : ProtoDecoratorBase
{
public override Type ExpectedType => forType;
private readonly FieldInfo field;
private readonly Type forType;
public override bool RequiresOldValue => true;
public override bool ReturnsValue => false;
public FieldDecorator(Type forType, FieldInfo field, IProtoSerializer tail) : base(tail)
{
Helpers.DebugAssert(forType != null);
Helpers.DebugAssert(field != null);
this.forType = forType;
this.field = field;
}
public override void Write(object value, ProtoWriter dest)
{
Helpers.DebugAssert(value != null);
value = field.GetValue(value);
if (value != null) Tail.Write(value, dest);
}
public override object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value != null);
object newValue = Tail.Read((Tail.RequiresOldValue ? field.GetValue(value) : null), source);
if (newValue != null) field.SetValue(value, newValue);
return null;
}
#if FEAT_COMPILER
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.LoadAddress(valueFrom, ExpectedType);
ctx.LoadValue(field);
ctx.WriteNullCheckedTail(field.FieldType, Tail, null);
}
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom))
{
if (Tail.RequiresOldValue)
{
ctx.LoadAddress(loc, ExpectedType);
ctx.LoadValue(field);
}
// value is either now on the stack or not needed
ctx.ReadNullCheckedTail(field.FieldType, Tail, null);
// the field could be a backing field that needs to be raised back to
// the property if we're doing a full compile
MemberInfo member = field;
ctx.CheckAccessibility(ref member);
bool writeValue = member is FieldInfo;
if (writeValue)
{
if (Tail.ReturnsValue)
{
using (Compiler.Local newVal = new Compiler.Local(ctx, field.FieldType))
{
ctx.StoreValue(newVal);
if (Helpers.IsValueType(field.FieldType))
{
ctx.LoadAddress(loc, ExpectedType);
ctx.LoadValue(newVal);
ctx.StoreValue(field);
}
else
{
Compiler.CodeLabel allDone = ctx.DefineLabel();
ctx.LoadValue(newVal);
ctx.BranchIfFalse(allDone, true); // interpret null as "don't assign"
ctx.LoadAddress(loc, ExpectedType);
ctx.LoadValue(newVal);
ctx.StoreValue(field);
ctx.MarkLabel(allDone);
}
}
}
}
else
{
// can't use result
if (Tail.ReturnsValue)
{
ctx.DiscardValue();
}
}
}
}
#endif
}
}
#endif