104 lines
3.8 KiB
C#
104 lines
3.8 KiB
C#
#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 |